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-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)
NEX-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)
2552 smbfs: add support for NFS-like remove
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
Reviewed by: Jason King <jason.king@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Approved by: Richard Lowe <richlowe@richlowe.net>

*** 26,55 **** * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $Id: smbfs_smb.c,v 1.73.38.1 2005/05/27 02:35:28 lindak Exp $ */ /* - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include <sys/param.h> #include <sys/systm.h> #include <sys/time.h> #include <sys/vnode.h> #include <sys/sunddi.h> #include <sys/cmn_err.h> #include <netsmb/smb_osdep.h> #include <netsmb/smb.h> #include <netsmb/smb_conn.h> #include <netsmb/smb_subr.h> #include <netsmb/smb_rq.h> #include <smbfs/smbfs.h> --- 26,56 ---- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include <sys/param.h> #include <sys/systm.h> + #include <sys/inttypes.h> #include <sys/time.h> #include <sys/vnode.h> #include <sys/sunddi.h> #include <sys/cmn_err.h> #include <netsmb/smb_osdep.h> #include <netsmb/smb.h> + #include <netsmb/smb2.h> #include <netsmb/smb_conn.h> #include <netsmb/smb_subr.h> #include <netsmb/smb_rq.h> #include <smbfs/smbfs.h>
*** 60,438 **** * Jan 1 1980 as 64 bit NT time. * (tenths of microseconds since 1601) */ const uint64_t NT1980 = 11960035200ULL*10000000ULL; - /* - * Local functions. - * Not static, to aid debugging. - */ - int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen, - struct smbfattr *fap, struct smb_cred *scrp); - int smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap, - struct smb_cred *scrp, uint16_t infolevel); - - int smbfs_smb_statfsLM1(struct smb_share *ssp, - statvfs64_t *sbp, struct smb_cred *scrp); - int smbfs_smb_statfsLM2(struct smb_share *ssp, - statvfs64_t *sbp, struct smb_cred *scrp); - - int smbfs_smb_setfattrNT(struct smbnode *np, int fid, - uint32_t attr, struct timespec *mtime, struct timespec *atime, - struct smb_cred *scrp); - - int smbfs_smb_setftime1(struct smbnode *np, uint16_t fid, - struct timespec *mtime, struct timespec *atime, - struct smb_cred *scrp); - - int smbfs_smb_setpattr1(struct smbnode *np, - const char *name, int len, uint32_t attr, - struct timespec *mtime, struct smb_cred *scrp); - - /* ! * Todo: locking over-the-wire */ ! #ifdef APPLE ! ! static int ! smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid, ! offset_t start, uint64_t len, int largelock, ! struct smb_cred *scrp, uint32_t timeout) { struct smb_share *ssp = np->n_mount->smi_share; - struct smb_rq rq, *rqp = &rq; - struct mbchain *mbp; - uint8_t ltype = 0; int error; ! /* Shared lock for n_fid use below. */ ! ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); ! ! /* After reconnect, n_fid is invalid */ ! if (np->n_vcgenid != ssp->ss_vcgenid) ! return (ESTALE); ! ! if (op == SMB_LOCK_SHARED) ! ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; ! /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */ ! if (largelock) ! ltype |= SMB_LOCKING_ANDX_LARGE_FILES; ! error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp); ! if (error) ! return (error); ! smb_rq_getrequest(rqp, &mbp); ! smb_rq_wstart(rqp); ! mb_put_uint8(mbp, 0xff); /* secondary command */ ! mb_put_uint8(mbp, 0); /* MBZ */ ! mb_put_uint16le(mbp, 0); ! mb_put_uint16le(mbp, np->n_fid); ! mb_put_uint8(mbp, ltype); /* locktype */ ! mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */ ! mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */ ! mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0); ! mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1); ! smb_rq_wend(rqp); ! smb_rq_bstart(rqp); ! mb_put_uint16le(mbp, pid); ! if (!largelock) { ! mb_put_uint32le(mbp, start); ! mb_put_uint32le(mbp, len); } else { ! mb_put_uint16le(mbp, 0); /* pad */ ! mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */ ! mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */ ! mb_put_uint32le(mbp, len >> 32); /* LengthHigh */ ! mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */ } - smb_rq_bend(rqp); - /* - * Don't want to risk missing a successful - * unlock send or lock response, or we could - * lose track of an outstanding lock. - */ - if (op == SMB_LOCK_RELEASE) - rqp->sr_flags |= SMBR_NOINTR_SEND; - else - rqp->sr_flags |= SMBR_NOINTR_RECV; - error = smb_rq_simple(rqp); - smb_rq_done(rqp); return (error); } - int - smbfs_smb_lock(struct smbnode *np, int op, caddr_t id, - offset_t start, uint64_t len, int largelock, - struct smb_cred *scrp, uint32_t timeout) - { - struct smb_share *ssp = np->n_mount->smi_share; - - if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0) - /* - * TODO: use LOCK_BYTE_RANGE here. - */ - return (EINVAL); - - /* - * XXX: compute largelock via: - * (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? - */ - return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len, - largelock, scrp, timeout)); - } - - #endif /* APPLE */ - /* ! * Helper for smbfs_getattr ! * Something like nfs_getattr_otw */ int ! smbfs_smb_getfattr( struct smbnode *np, struct smbfattr *fap, struct smb_cred *scrp) { int error; ! /* ! * This lock is necessary for FID-based calls. ! * Lock may be writer (via open) or reader. ! */ ! ASSERT(np->r_lkserlock.count != 0); ! ! /* ! * Extended attribute directory or file. ! */ ! if (np->n_flag & N_XATTR) { ! error = smbfs_xa_getfattr(np, fap, scrp); ! return (error); } - error = smbfs_smb_trans2_query(np, fap, scrp, 0); - if (error != EINVAL) return (error); - - /* fallback */ - error = smbfs_smb_query_info(np, NULL, 0, fap, scrp); - - return (error); } /* ! * Common function for QueryFileInfo, QueryPathInfo. */ int - smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap, - struct smb_cred *scrp, uint16_t infolevel) - { - struct smb_share *ssp = np->n_mount->smi_share; - struct smb_vc *vcp = SSTOVC(ssp); - struct smb_t2rq *t2p; - int error, svtz, timesok = 1; - struct mbchain *mbp; - struct mdchain *mdp; - uint16_t cmd, date, time, wattr; - uint64_t llongint, lsize; - uint32_t size, dattr; - - /* - * Shared lock for n_fid use below. - * See smbfs_smb_getfattr() - */ - ASSERT(np->r_lkserlock.count != 0); - - /* - * If we have a valid open FID, use it. - */ - if ((np->n_fidrefs > 0) && - (np->n_fid != SMB_FID_UNUSED) && - (np->n_vcgenid == ssp->ss_vcgenid)) - cmd = SMB_TRANS2_QUERY_FILE_INFORMATION; - else - cmd = SMB_TRANS2_QUERY_PATH_INFORMATION; - - top: - error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p); - if (error) - return (error); - mbp = &t2p->t2_tparam; - mb_init(mbp); - if (!infolevel) { - if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) - infolevel = SMB_QFILEINFO_STANDARD; - else - infolevel = SMB_QFILEINFO_ALL_INFO; - } - - if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION) - mb_put_uint16le(mbp, np->n_fid); - - mb_put_uint16le(mbp, infolevel); - - if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) { - mb_put_uint32le(mbp, 0); - /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */ - error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\'); - if (error) { - smb_t2_done(t2p); - return (error); - } - } - - t2p->t2_maxpcount = 2; - t2p->t2_maxdcount = vcp->vc_txmax; - error = smb_t2_request(t2p); - if (error) { - smb_t2_done(t2p); - /* Invalid info level? Try fallback. */ - if (error == EINVAL && - infolevel == SMB_QFILEINFO_ALL_INFO) { - infolevel = SMB_QFILEINFO_STANDARD; - goto top; - } - return (error); - } - mdp = &t2p->t2_rdata; - svtz = vcp->vc_sopt.sv_tz; - switch (infolevel) { - case SMB_QFILEINFO_STANDARD: - md_get_uint16le(mdp, &date); - md_get_uint16le(mdp, &time); /* creation time */ - smb_dos2unixtime(date, time, 0, svtz, &fap->fa_createtime); - md_get_uint16le(mdp, &date); - md_get_uint16le(mdp, &time); /* access time */ - smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); - md_get_uint16le(mdp, &date); - md_get_uint16le(mdp, &time); /* modify time */ - smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); - md_get_uint32le(mdp, &size); /* EOF position */ - fap->fa_size = size; - md_get_uint32le(mdp, &size); /* allocation size */ - fap->fa_allocsz = size; - error = md_get_uint16le(mdp, &wattr); - fap->fa_attr = wattr; - timesok = 1; - break; - case SMB_QFILEINFO_ALL_INFO: - timesok = 0; - /* creation time */ - md_get_uint64le(mdp, &llongint); - if (llongint) - timesok++; - smb_time_NT2local(llongint, &fap->fa_createtime); - - /* last access time */ - md_get_uint64le(mdp, &llongint); - if (llongint) - timesok++; - smb_time_NT2local(llongint, &fap->fa_atime); - - /* last write time */ - md_get_uint64le(mdp, &llongint); - if (llongint) - timesok++; - smb_time_NT2local(llongint, &fap->fa_mtime); - - /* last change time */ - md_get_uint64le(mdp, &llongint); - if (llongint) - timesok++; - smb_time_NT2local(llongint, &fap->fa_ctime); - - /* attributes */ - md_get_uint32le(mdp, &dattr); - fap->fa_attr = dattr; - - /* - * 4-Byte alignment - discard - * Specs don't talk about this. - */ - md_get_uint32le(mdp, NULL); - /* allocation size */ - md_get_uint64le(mdp, &lsize); - fap->fa_allocsz = lsize; - /* File size */ - error = md_get_uint64le(mdp, &lsize); - fap->fa_size = lsize; - break; - default: - SMBVDEBUG("unexpected info level %d\n", infolevel); - error = EINVAL; - } - smb_t2_done(t2p); - /* - * if all times are zero (observed with FAT on NT4SP6) - * then fall back to older info level - */ - if (!timesok) { - if (infolevel == SMB_QFILEINFO_ALL_INFO) { - infolevel = SMB_QFILEINFO_STANDARD; - goto top; - } - error = EINVAL; - } - return (error); - } - - /* - * Support functions for _qstreaminfo - * Moved to smbfs_xattr.c - */ - - int smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa, struct smb_cred *scrp) { - struct smb_t2rq *t2p; - struct mbchain *mbp; - struct mdchain *mdp; int error; - uint32_t nlen; ! error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, ! scrp, &t2p); ! if (error) ! return (error); ! mbp = &t2p->t2_tparam; ! mb_init(mbp); ! mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO); ! t2p->t2_maxpcount = 4; ! t2p->t2_maxdcount = 4 * 3 + 512; ! error = smb_t2_request(t2p); ! if (error) ! goto out; ! ! mdp = &t2p->t2_rdata; ! md_get_uint32le(mdp, &fsa->fsa_aflags); ! md_get_uint32le(mdp, &fsa->fsa_maxname); ! error = md_get_uint32le(mdp, &nlen); /* fs name length */ ! if (error) ! goto out; ! ! /* ! * Get the FS type name. ! */ ! bzero(fsa->fsa_tname, FSTYPSZ); ! if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) { ! uint16_t tmpbuf[FSTYPSZ]; ! size_t tmplen, outlen; ! ! if (nlen > sizeof (tmpbuf)) ! nlen = sizeof (tmpbuf); ! error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM); ! tmplen = nlen / 2; /* UCS-2 chars */ ! outlen = FSTYPSZ - 1; ! (void) uconv_u16tou8(tmpbuf, &tmplen, ! (uchar_t *)fsa->fsa_tname, &outlen, ! UCONV_IN_LITTLE_ENDIAN); } else { ! if (nlen > (FSTYPSZ - 1)) ! nlen = FSTYPSZ - 1; ! error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM); } /* * If fs_name starts with FAT, we can't set dates before 1980 */ --- 61,134 ---- * Jan 1 1980 as 64 bit NT time. * (tenths of microseconds since 1601) */ const uint64_t NT1980 = 11960035200ULL*10000000ULL; /* ! * Helper for smbfs_getattr_otw ! * used when we have an open FID */ ! int ! smbfs_smb_getfattr( ! struct smbnode *np, ! smb_fh_t *fhp, ! struct smbfattr *fap, ! struct smb_cred *scrp) { struct smb_share *ssp = np->n_mount->smi_share; int error; ! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { ! error = smbfs_smb2_qfileinfo(ssp, &fhp->fh_fid2, fap, scrp); } else { ! error = smbfs_smb1_trans2_query(np, fhp->fh_fid1, fap, scrp); } return (error); } /* ! * Helper for smbfs_getattr_otw ! * used when we don't have an open FID ! * ! * For SMB1 we can just use the path form of trans2 query. ! * For SMB2 we need to do an attribute-only open. ! * See smbfs_smb2_getpattr() */ int ! smbfs_smb_getpattr( struct smbnode *np, struct smbfattr *fap, struct smb_cred *scrp) { + struct smb_share *ssp = np->n_mount->smi_share; int error; ! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { ! error = smbfs_smb2_getpattr(np, fap, scrp); ! } else { ! uint16_t fid = SMB_FID_UNUSED; ! error = smbfs_smb1_trans2_query(np, fid, fap, scrp); } return (error); } /* ! * Get and parse FileFsAttributeInformation */ int smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa, struct smb_cred *scrp) { int error; ! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { ! error = smbfs_smb2_qfsattr(ssp, fsa, scrp); } else { ! error = smbfs_smb1_qfsattr(ssp, fsa, scrp); } /* * If fs_name starts with FAT, we can't set dates before 1980 */
*** 440,1104 **** SMB_SS_LOCK(ssp); ssp->ss_flags |= SMBS_FST_FAT; SMB_SS_UNLOCK(ssp); } ! out: ! smb_t2_done(t2p); ! return (0); } int smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp, struct smb_cred *scp) { int error; ! if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) ! error = smbfs_smb_statfsLM2(ssp, sbp, scp); ! else ! error = smbfs_smb_statfsLM1(ssp, sbp, scp); ! return (error); - } ! int ! smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp, ! struct smb_cred *scrp) ! { ! struct smb_t2rq *t2p; ! struct mbchain *mbp; ! struct mdchain *mdp; ! uint16_t bsize; ! uint32_t units, bpu, funits; ! uint64_t s, t, f; ! int error; ! error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION, ! scrp, &t2p); ! if (error) ! return (error); ! mbp = &t2p->t2_tparam; ! mb_init(mbp); ! mb_put_uint16le(mbp, SMB_QFS_ALLOCATION); ! t2p->t2_maxpcount = 4; ! t2p->t2_maxdcount = 4 * 4 + 2; ! error = smb_t2_request(t2p); ! if (error) ! goto out; ! mdp = &t2p->t2_rdata; ! md_get_uint32le(mdp, NULL); /* fs id */ ! md_get_uint32le(mdp, &bpu); ! md_get_uint32le(mdp, &units); ! md_get_uint32le(mdp, &funits); ! error = md_get_uint16le(mdp, &bsize); ! if (error) ! goto out; ! s = bsize; ! s *= bpu; ! t = units; ! f = funits; ! /* ! * Don't allow over-large blocksizes as they determine ! * Finder List-view size granularities. On the other ! * hand, we mustn't let the block count overflow the ! * 31 bits available. ! */ ! while (s > 16 * 1024) { ! if (t > LONG_MAX) ! break; ! s /= 2; ! t *= 2; ! f *= 2; ! } ! while (t > LONG_MAX) { ! t /= 2; ! f /= 2; ! s *= 2; ! } ! sbp->f_bsize = (ulong_t)s; /* file system block size */ ! sbp->f_blocks = t; /* total data blocks in file system */ ! sbp->f_bfree = f; /* free blocks in fs */ ! sbp->f_bavail = f; /* free blocks avail to non-superuser */ ! sbp->f_files = (-1); /* total file nodes in file system */ ! sbp->f_ffree = (-1); /* free file nodes in fs */ ! out: ! smb_t2_done(t2p); ! return (0); ! } ! int ! smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp, ! struct smb_cred *scrp) ! { ! struct smb_rq rq, *rqp = &rq; ! struct mdchain *mdp; ! uint16_t units, bpu, bsize, funits; ! uint64_t s, t, f; ! int error; ! error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, ! scrp); ! if (error) ! return (error); ! smb_rq_wstart(rqp); ! smb_rq_wend(rqp); ! smb_rq_bstart(rqp); ! smb_rq_bend(rqp); ! error = smb_rq_simple(rqp); ! if (error) ! goto out; - smb_rq_getreply(rqp, &mdp); - md_get_uint16le(mdp, &units); - md_get_uint16le(mdp, &bpu); - md_get_uint16le(mdp, &bsize); - error = md_get_uint16le(mdp, &funits); - if (error) - goto out; - s = bsize; - s *= bpu; - t = units; - f = funits; - /* - * Don't allow over-large blocksizes as they determine - * Finder List-view size granularities. On the other - * hand, we mustn't let the block count overflow the - * 31 bits available. - */ - while (s > 16 * 1024) { - if (t > LONG_MAX) - break; - s /= 2; - t *= 2; - f *= 2; - } - while (t > LONG_MAX) { - t /= 2; - f /= 2; - s *= 2; - } - sbp->f_bsize = (ulong_t)s; /* file system block size */ - sbp->f_blocks = t; /* total data blocks in file system */ - sbp->f_bfree = f; /* free blocks in fs */ - sbp->f_bavail = f; /* free blocks avail to non-superuser */ sbp->f_files = (-1); /* total file nodes in file system */ sbp->f_ffree = (-1); /* free file nodes in fs */ - out: - smb_rq_done(rqp); - return (0); - } - - int - smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize, - struct smb_cred *scrp) - { - struct smb_t2rq *t2p; - struct smb_vc *vcp = SSTOVC(ssp); - struct mbchain *mbp; - int error; - - error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, - scrp, &t2p); - if (error) return (error); - mbp = &t2p->t2_tparam; - mb_init(mbp); - mb_put_uint16le(mbp, fid); - if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) - mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION); - else - mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO); - mb_put_uint16le(mbp, 0); /* pad */ - mbp = &t2p->t2_tdata; - mb_init(mbp); - mb_put_uint64le(mbp, newsize); - t2p->t2_maxpcount = 2; - t2p->t2_maxdcount = 0; - error = smb_t2_request(t2p); - smb_t2_done(t2p); - return (error); } - /*ARGSUSED*/ int ! smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp, ! const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite) { ! struct smb_t2rq *t2p; ! struct smb_share *ssp = np->n_mount->smi_share; ! struct smb_vc *vcp = SSTOVC(ssp); ! struct mbchain *mbp; ! int32_t *ucslenp; ! int error, cerror; ! uint16_t fid = 0; ! /* Shared lock for n_fid use below. */ ! ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); ! ! /* After reconnect, n_fid is invalid */ ! if (np->n_vcgenid != ssp->ss_vcgenid) ! return (ESTALE); ! ! if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)) ! return (ENOTSUP); ! error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, ! scrp, &t2p); ! if (error) ! return (error); ! if (tdnp) { ! error = smbfs_smb_tmpopen(tdnp, SA_RIGHT_FILE_READ_DATA, scrp, ! &fid); ! if (error) ! goto exit; } - mbp = &t2p->t2_tparam; - mb_init(mbp); - mb_put_uint16le(mbp, np->n_fid); - mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION); - mb_put_uint16le(mbp, 0); /* reserved, nowadays */ - mbp = &t2p->t2_tdata; - mb_init(mbp); - mb_put_uint32le(mbp, overwrite); - mb_put_uint16le(mbp, fid); /* base for tname */ - mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */ - ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t)); - mbp->mb_count = 0; - error = smb_put_dstring(mbp, vcp, tname, SMB_CS_NONE); - if (error) - goto exit; - mbp->mb_count--; /* don't count the null */ - *ucslenp = htolel(mbp->mb_count); - t2p->t2_maxpcount = 2; - t2p->t2_maxdcount = 0; - error = smb_t2_request(t2p); - exit: - if (fid) { - cerror = smbfs_smb_tmpclose(tdnp, fid, scrp); - if (cerror) - SMBVDEBUG("error %d closing %s\n", - cerror, tdnp->n_rpath); - } - smb_t2_done(t2p); - return (error); - } ! int ! smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp) ! { ! struct smb_share *ssp = np->n_mount->smi_share; ! struct smb_rq rq, *rqp = &rq; ! struct mbchain *mbp; ! int error; ! ! /* Shared lock for n_fid use below. */ ! ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); ! ! if (!(np->n_flag & NFLUSHWIRE)) ! return (0); ! if (np->n_fidrefs == 0) ! return (0); /* not open */ ! ! /* After reconnect, n_fid is invalid */ ! if (np->n_vcgenid != ssp->ss_vcgenid) ! return (ESTALE); ! ! error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp); ! if (error) ! return (error); ! smb_rq_getrequest(rqp, &mbp); ! smb_rq_wstart(rqp); ! mb_put_uint16le(mbp, np->n_fid); ! smb_rq_wend(rqp); ! smb_rq_bstart(rqp); ! smb_rq_bend(rqp); ! error = smb_rq_simple(rqp); ! smb_rq_done(rqp); ! if (!error) { ! mutex_enter(&np->r_statelock); ! np->n_flag &= ~NFLUSHWIRE; ! mutex_exit(&np->r_statelock); ! } ! return (error); } int ! smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize, ! struct smb_cred *scrp) { - struct smb_share *ssp = np->n_mount->smi_share; - struct smb_rq rq, *rqp = &rq; - struct mbchain *mbp; int error; ! if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { ! /* ! * This call knows about 64-bit offsets. ! */ ! error = smbfs_smb_seteof(ssp, fid, newsize, scrp); ! if (!error) { ! mutex_enter(&np->r_statelock); ! np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); ! mutex_exit(&np->r_statelock); ! return (0); } - } - /* - * OK, so fallback to SMB_COM_WRITE, but note: - * it only supports 32-bit file offsets. - */ - if (newsize > UINT32_MAX) - return (EFBIG); - - error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp); - if (error) return (error); - smb_rq_getrequest(rqp, &mbp); - smb_rq_wstart(rqp); - mb_put_uint16le(mbp, fid); - mb_put_uint16le(mbp, 0); - mb_put_uint32le(mbp, newsize); - mb_put_uint16le(mbp, 0); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - mb_put_uint8(mbp, SMB_DT_DATA); - mb_put_uint16le(mbp, 0); - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - smb_rq_done(rqp); - mutex_enter(&np->r_statelock); - np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); - mutex_exit(&np->r_statelock); - return (error); } - /* - * Old method for getting file attributes. - */ - int - smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen, - struct smbfattr *fap, struct smb_cred *scrp) - { - struct smb_rq rq, *rqp = &rq; - struct smb_share *ssp = np->n_mount->smi_share; - struct mbchain *mbp; - struct mdchain *mdp; - uint8_t wc; - int error; - uint16_t wattr; - uint32_t longint; - error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp); - if (error) - return (error); - smb_rq_getrequest(rqp, &mbp); - smb_rq_wstart(rqp); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - mb_put_uint8(mbp, SMB_DT_ASCII); - - error = smbfs_fullpath(mbp, SSTOVC(ssp), np, - name, nmlen, '\\'); - if (error) - goto out; - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - if (error) - goto out; - smb_rq_getreply(rqp, &mdp); - error = md_get_uint8(mdp, &wc); - if (error) - goto out; - if (wc != 10) { - error = EBADRPC; - goto out; - } - md_get_uint16le(mdp, &wattr); - fap->fa_attr = wattr; - /* - * Be careful using the time returned here, as - * with FAT on NT4SP6, at least, the time returned is low - * 32 bits of 100s of nanoseconds (since 1601) so it rolls - * over about every seven minutes! - */ - md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */ - smb_time_server2local(longint, - SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime); - error = md_get_uint32le(mdp, &longint); - fap->fa_size = longint; - - out: - smb_rq_done(rqp); - return (error); - } - /* - * Set DOS file attributes. mtime should be NULL for dialects above lm10 - */ - int - smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len, - uint32_t attr, struct timespec *mtime, - struct smb_cred *scrp) - { - struct smb_rq rq, *rqp = &rq; - struct smb_share *ssp = np->n_mount->smi_share; - struct mbchain *mbp; - long time; - int error, svtz; - - error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp); - if (error) - return (error); - svtz = SSTOVC(ssp)->vc_sopt.sv_tz; - smb_rq_getrequest(rqp, &mbp); - smb_rq_wstart(rqp); - mb_put_uint16le(mbp, (uint16_t)attr); - if (mtime) { - smb_time_local2server(mtime, svtz, &time); - } else - time = 0; - mb_put_uint32le(mbp, time); /* mtime */ - mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - mb_put_uint8(mbp, SMB_DT_ASCII); - - error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len, '\\'); - if (error) - goto out; - mb_put_uint8(mbp, SMB_DT_ASCII); - if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) { - mb_put_padbyte(mbp); - mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */ - } - mb_put_uint8(mbp, 0); - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - - out: - smb_rq_done(rqp); - return (error); - } - - int - smbfs_smb_hideit(struct smbnode *np, const char *name, int len, - struct smb_cred *scrp) - { - struct smbfattr fa; - int error; - uint32_t attr; - - error = smbfs_smb_query_info(np, name, len, &fa, scrp); - attr = fa.fa_attr; - if (!error && !(attr & SMB_FA_HIDDEN)) { - attr |= SMB_FA_HIDDEN; - error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp); - } - return (error); - } - - - int - smbfs_smb_unhideit(struct smbnode *np, const char *name, int len, - struct smb_cred *scrp) - { - struct smbfattr fa; - uint32_t attr; - int error; - - error = smbfs_smb_query_info(np, name, len, &fa, scrp); - attr = fa.fa_attr; - if (!error && (attr & SMB_FA_HIDDEN)) { - attr &= ~SMB_FA_HIDDEN; - error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp); - } - return (error); - } - - /* * Set file attributes (optionally: DOS attr, atime, mtime) ! * either by open FID or by path name (FID == -1). */ int smbfs_smb_setfattr( ! struct smbnode *np, ! int fid, uint32_t attr, struct timespec *mtime, struct timespec *atime, struct smb_cred *scrp) { ! struct smb_share *ssp = np->n_mount->smi_share; ! struct smb_vc *vcp = SSTOVC(ssp); int error; /* ! * Normally can use the trans2 call. */ - if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { - error = smbfs_smb_setfattrNT(np, fid, - attr, mtime, atime, scrp); - return (error); - } - - /* - * Fall-back for older protocols. - */ - if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { - error = smbfs_smb_setftime1(np, fid, - mtime, atime, scrp); - return (error); - } - error = smbfs_smb_setpattr1(np, NULL, 0, - attr, mtime, scrp); - return (error); - } - - /* - * Set file atime and mtime. Isn't supported by core dialect. - */ - int - smbfs_smb_setftime1( - struct smbnode *np, - uint16_t fid, - struct timespec *mtime, - struct timespec *atime, - struct smb_cred *scrp) - { - struct smb_rq rq, *rqp = &rq; - struct smb_share *ssp = np->n_mount->smi_share; - struct mbchain *mbp; - uint16_t date, time; - int error, tzoff; - - error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp); - if (error) - return (error); - - tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; - smb_rq_getrequest(rqp, &mbp); - smb_rq_wstart(rqp); - mb_put_uint16le(mbp, fid); - mb_put_uint32le(mbp, 0); /* creation time */ - - if (atime) - smb_time_unix2dos(atime, tzoff, &date, &time, NULL); - else - time = date = 0; - mb_put_uint16le(mbp, date); - mb_put_uint16le(mbp, time); - if (mtime) - smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); - else - time = date = 0; - mb_put_uint16le(mbp, date); - mb_put_uint16le(mbp, time); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - SMBVDEBUG("%d\n", error); - smb_rq_done(rqp); - return (error); - } - - /* - * Set DOS file attributes, either via open FID or by path name. - * Looks like this call can be used only if CAP_NT_SMBS bit is on. - * - * When setting via path (fid == -1): - * *BASIC_INFO works with Samba, but Win2K servers say it is an - * invalid information level on a SET_PATH_INFO. Note Win2K does - * support *BASIC_INFO on a SET_FILE_INFO, and they support the - * equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure. - */ - int - smbfs_smb_setfattrNT( - struct smbnode *np, - int fid, /* if fid == -1, set by path */ - uint32_t attr, - struct timespec *mtime, - struct timespec *atime, - struct smb_cred *scrp) - { - struct smb_t2rq *t2p; - struct smb_share *ssp = np->n_mount->smi_share; - struct smb_vc *vcp = SSTOVC(ssp); - struct mbchain *mbp; - uint64_t tm; - int error; - uint16_t cmd, level; - - if (fid == -1) { - cmd = SMB_TRANS2_SET_PATH_INFORMATION; - } else { - if (fid > UINT16_MAX) - return (EINVAL); - cmd = SMB_TRANS2_SET_FILE_INFORMATION; - } - if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) - level = SMB_SFILEINFO_BASIC_INFORMATION; - else - level = SMB_SFILEINFO_BASIC_INFO; - - error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p); - if (error) - return (error); - - mbp = &t2p->t2_tparam; mb_init(mbp); - - if (cmd == SMB_TRANS2_SET_FILE_INFORMATION) - mb_put_uint16le(mbp, fid); - - mb_put_uint16le(mbp, level); - mb_put_uint32le(mbp, 0); /* MBZ */ - - if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) { - error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\'); - if (error != 0) - goto out; - } - - /* FAT file systems don't support dates earlier than 1980. */ - - mbp = &t2p->t2_tdata; - mb_init(mbp); mb_put_uint64le(mbp, 0); /* creation time */ if (atime) { smb_time_local2NT(atime, &tm); if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) && tm < NT1980) tm = NT1980; } else tm = 0; ! mb_put_uint64le(mbp, tm); /* access time */ if (mtime) { smb_time_local2NT(mtime, &tm); if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) && tm < NT1980) tm = NT1980; } else tm = 0; mb_put_uint64le(mbp, tm); /* last write time */ ! mb_put_uint64le(mbp, 0); /* ctime (no change) */ mb_put_uint32le(mbp, attr); ! mb_put_uint32le(mbp, 0); /* padding */ ! t2p->t2_maxpcount = 2; ! t2p->t2_maxdcount = 0; ! error = smb_t2_request(t2p); ! out: ! smb_t2_done(t2p); return (error); } /* * Modern create/open of file or directory. */ int smbfs_smb_ntcreatex( struct smbnode *np, const char *name, --- 136,299 ---- SMB_SS_LOCK(ssp); ssp->ss_flags |= SMBS_FST_FAT; SMB_SS_UNLOCK(ssp); } ! return (error); } int smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp, struct smb_cred *scp) { + struct smb_fs_size_info info; + struct smb_vc *vcp = SSTOVC(ssp); + uint32_t bps, spu; int error; ! if (vcp->vc_flags & SMBV_SMB2) { ! error = smbfs_smb2_statfs(ssp, &info, scp); ! } else { ! error = smbfs_smb1_statfs(ssp, &info, scp); ! } ! if (error) return (error); ! /* A bit of paranoia. */ ! bps = info.bytes_per_sect; ! if (bps < DEV_BSIZE) ! bps = DEV_BSIZE; ! spu = info.sect_per_unit; ! if (spu == 0) ! spu = 1; ! /* preferred file system block size */ ! sbp->f_bsize = bps * spu; ! /* file system block size ("fragment size") */ ! sbp->f_frsize = bps; ! /* total blocks of f_frsize */ ! sbp->f_blocks = info.total_units * spu; ! /* free blocks of f_frsize */ ! sbp->f_bfree = info.actual_avail * spu; ! /* free blocks avail to non-superuser */ ! sbp->f_bavail = info.caller_avail * spu; sbp->f_files = (-1); /* total file nodes in file system */ sbp->f_ffree = (-1); /* free file nodes in fs */ return (error); } int ! smbfs_smb_setdisp(struct smb_share *ssp, smb_fh_t *fhp, ! uint8_t disp, struct smb_cred *scrp) { ! int err; ! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { ! err = smbfs_smb2_setdisp(ssp, &fhp->fh_fid2, disp, scrp); ! } else { ! err = smbfs_smb1_setdisp(ssp, fhp->fh_fid1, disp, scrp); } ! return (err); } int ! smbfs_smb_setfsize(struct smb_share *ssp, smb_fh_t *fhp, ! uint64_t size, struct smb_cred *scrp) { int error; ! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { ! error = smbfs_smb2_seteof(ssp, &fhp->fh_fid2, size, scrp); ! } else { ! error = smbfs_smb1_seteof(ssp, fhp->fh_fid1, size, scrp); } return (error); } /* * Set file attributes (optionally: DOS attr, atime, mtime) ! * Always have an open FID with set attr rights. */ int smbfs_smb_setfattr( ! struct smb_share *ssp, ! smb_fh_t *fhp, uint32_t attr, struct timespec *mtime, struct timespec *atime, struct smb_cred *scrp) { ! struct mbchain mb_info; ! struct mbchain *mbp = &mb_info; ! uint64_t tm; int error; /* ! * Build a struct FILE_BASIC_INFORMATION in mbp ! * LARGE_INTEGER CreationTime; ! * LARGE_INTEGER LastAccessTime; ! * LARGE_INTEGER LastWriteTime; ! * LARGE_INTEGER ChangeTime; ! * ULONG FileAttributes; ! * Zero in times means "no change". */ mb_init(mbp); mb_put_uint64le(mbp, 0); /* creation time */ if (atime) { smb_time_local2NT(atime, &tm); if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) && tm < NT1980) tm = NT1980; } else tm = 0; ! mb_put_uint64le(mbp, tm); /* last access time */ if (mtime) { smb_time_local2NT(mtime, &tm); if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) && tm < NT1980) tm = NT1980; } else tm = 0; mb_put_uint64le(mbp, tm); /* last write time */ ! mb_put_uint64le(mbp, 0); /* change time */ mb_put_uint32le(mbp, attr); ! ! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { ! error = smbfs_smb2_setfattr(ssp, &fhp->fh_fid2, mbp, scrp); ! } else { ! error = smbfs_smb1_setfattr(ssp, fhp->fh_fid1, mbp, scrp); ! } ! return (error); } + int + smbfs_smb_flush(struct smb_share *ssp, smb_fh_t *fhp, + struct smb_cred *scrp) + { + int error; + + if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) { + error = smbfs_smb2_flush(ssp, &fhp->fh_fid2, scrp); + } else { + error = smbfs_smb1_flush(ssp, fhp->fh_fid1, scrp); + } + return (error); + } + /* * Modern create/open of file or directory. + * On success, fills in fhp->fh_fid* and fhp->fh_rights */ int smbfs_smb_ntcreatex( struct smbnode *np, const char *name,
*** 1108,1118 **** uint32_t efa, /* ext. file attrs (DOS attr +) */ uint32_t share_acc, uint32_t disp, /* open disposition */ uint32_t createopt, /* NTCREATEX_OPTIONS_ */ struct smb_cred *scrp, ! uint16_t *fidp, /* returned FID */ uint32_t *cr_act_p, /* optional returned create action */ struct smbfattr *fap) /* optional returned attributes */ { struct mbchain name_mb; struct smb_share *ssp = np->n_mount->smi_share; --- 303,313 ---- uint32_t efa, /* ext. file attrs (DOS attr +) */ uint32_t share_acc, uint32_t disp, /* open disposition */ uint32_t createopt, /* NTCREATEX_OPTIONS_ */ struct smb_cred *scrp, ! smb_fh_t *fhp, /* pre-made file handle to fill in */ uint32_t *cr_act_p, /* optional returned create action */ struct smbfattr *fap) /* optional returned attributes */ { struct mbchain name_mb; struct smb_share *ssp = np->n_mount->smi_share;
*** 1129,1373 **** err = smb_smb_ntcreate(ssp, &name_mb, 0, /* NTCREATEX_FLAGS... */ req_acc, efa, share_acc, disp, createopt, NTCREATEX_IMPERSONATION_IMPERSONATION, ! scrp, fidp, cr_act_p, fap); out: mb_done(&name_mb); return (err); } ! static uint32_t ! smb_mode2rights(int mode) ! { ! mode = mode & SMB_AM_OPENMODE; ! uint32_t rights = ! STD_RIGHT_SYNCHRONIZE_ACCESS | ! STD_RIGHT_READ_CONTROL_ACCESS; ! ! if ((mode == SMB_AM_OPENREAD) || ! (mode == SMB_AM_OPENRW)) { ! rights |= ! SA_RIGHT_FILE_READ_ATTRIBUTES | ! SA_RIGHT_FILE_READ_DATA; ! } ! ! if ((mode == SMB_AM_OPENWRITE) || ! (mode == SMB_AM_OPENRW)) { ! rights |= ! SA_RIGHT_FILE_WRITE_ATTRIBUTES | ! SA_RIGHT_FILE_APPEND_DATA | ! SA_RIGHT_FILE_WRITE_DATA; ! } ! ! if (mode == SMB_AM_OPENEXEC) { ! rights |= ! SA_RIGHT_FILE_READ_ATTRIBUTES | ! SA_RIGHT_FILE_EXECUTE; ! } ! ! return (rights); ! } ! ! static int ! smb_rights2mode(uint32_t rights) ! { ! int accmode = SMB_AM_OPENEXEC; /* our fallback */ ! ! if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD | ! SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES | ! SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS | ! STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS)) ! accmode = SMB_AM_OPENWRITE; ! if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES | ! SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS)) ! accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD ! : SMB_AM_OPENRW; ! return (accmode); ! } ! ! static int ! smbfs_smb_oldopen( ! struct smbnode *np, ! const char *name, ! int nmlen, ! int xattr, ! int accmode, ! struct smb_cred *scrp, ! uint16_t *fidp, ! uint16_t *granted_mode_p, ! smbfattr_t *fap) ! { ! struct smb_rq rq, *rqp = &rq; ! struct smb_share *ssp = np->n_mount->smi_share; ! struct smb_vc *vcp = SSTOVC(ssp); ! struct mbchain *mbp; ! struct mdchain *mdp; ! struct smbfattr fa; ! uint8_t wc; ! uint16_t wattr; ! uint32_t longint; ! int error; ! ! bzero(&fa, sizeof (fa)); ! ! /* ! * XXX: move to callers... * ! * Use DENYNONE to give unixy semantics of permitting ! * everything not forbidden by permissions. Ie denial ! * is up to server with clients/openers needing to use ! * advisory locks for further control. */ - accmode |= SMB_SM_DENYNONE; - - error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp); - if (error) - return (error); - smb_rq_getrequest(rqp, &mbp); - smb_rq_wstart(rqp); - mb_put_uint16le(mbp, accmode); - mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY | - SMB_FA_DIR); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - mb_put_uint8(mbp, SMB_DT_ASCII); - - error = smbfs_fullpath(mbp, vcp, np, name, nmlen, - xattr ? ':' : '\\'); - if (error) - goto done; - smb_rq_bend(rqp); - /* - * Don't want to risk missing a successful - * open response, or we could "leak" FIDs. - */ - rqp->sr_flags |= SMBR_NOINTR_RECV; - error = smb_rq_simple_timed(rqp, smb_timo_open); - if (error) - goto done; - smb_rq_getreply(rqp, &mdp); - /* - * 8/2002 a DAVE server returned wc of 15 so we ignore that. - * (the actual packet length and data was correct) - */ - error = md_get_uint8(mdp, &wc); - if (error) - goto done; - if (wc != 7 && wc != 15) { - error = EBADRPC; - goto done; - } - md_get_uint16le(mdp, fidp); - md_get_uint16le(mdp, &wattr); - fa.fa_attr = wattr; - /* - * Be careful using the time returned here, as - * with FAT on NT4SP6, at least, the time returned is low - * 32 bits of 100s of nanoseconds (since 1601) so it rolls - * over about every seven minutes! - */ - md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */ - smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime); - md_get_uint32le(mdp, &longint); - fa.fa_size = longint; - error = md_get_uint16le(mdp, granted_mode_p); - - done: - smb_rq_done(rqp); - if (error) - return (error); - - if (fap) - *fap = fa; /* struct copy */ - - return (0); - } - int smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, ! uint16_t *fidp) { struct smb_share *ssp = np->n_mount->smi_share; ! struct smb_vc *vcp = SSTOVC(ssp); ! int accmode, error; - /* Shared lock for n_fid use below. */ - ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); - /* Can we re-use n_fid? or must we open anew? */ mutex_enter(&np->r_statelock); if (np->n_fidrefs > 0 && ! np->n_vcgenid == ssp->ss_vcgenid && ! (rights & np->n_rights) == rights) { ! np->n_fidrefs++; ! *fidp = np->n_fid; mutex_exit(&np->r_statelock); return (0); } mutex_exit(&np->r_statelock); /* re-open an existing file. */ - if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { error = smbfs_smb_ntcreatex(np, NULL, 0, 0, /* name nmlen xattr */ rights, SMB_EFA_NORMAL, NTCREATEX_SHARE_ACCESS_ALL, NTCREATEX_DISP_OPEN, 0, /* create options */ ! scrp, fidp, NULL, NULL); /* cr_act_p fa_p */ ! return (error); ! } ! accmode = smb_rights2mode(rights); ! error = smbfs_smb_oldopen(np, ! NULL, 0, 0, /* name nmlen xattr */ ! accmode, scrp, ! fidp, ! NULL, /* granted mode p */ ! NULL); /* fa p */ return (error); } ! int ! smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp) { ! struct smb_share *ssp = np->n_mount->smi_share; ! int error = 0; ! uint16_t oldfid = SMB_FID_UNUSED; ! ! /* Shared lock for n_fid use below. */ ! ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); ! ! mutex_enter(&np->r_statelock); ! if (fid == np->n_fid) { ! ASSERT(np->n_fidrefs > 0); ! if (--np->n_fidrefs == 0) { ! /* ! * Don't expect to find the last reference ! * here in tmpclose. Hard to deal with as ! * we don't have r_lkserlock exclusive. ! * Will close oldfid below. ! */ ! oldfid = np->n_fid; ! np->n_fid = SMB_FID_UNUSED; ! } ! } else { ! /* Will close the passed fid. */ ! oldfid = fid; ! } ! mutex_exit(&np->r_statelock); ! ! if (oldfid != SMB_FID_UNUSED) ! error = smbfs_smb_close(ssp, oldfid, NULL, scrp); ! ! return (error); } int smbfs_smb_open( struct smbnode *np, --- 324,403 ---- err = smb_smb_ntcreate(ssp, &name_mb, 0, /* NTCREATEX_FLAGS... */ req_acc, efa, share_acc, disp, createopt, NTCREATEX_IMPERSONATION_IMPERSONATION, ! scrp, fhp, cr_act_p, fap); out: mb_done(&name_mb); return (err); } ! /* ! * Get a file handle with (at least) the specified rights. * ! * We'll try to borrow the node ->n_fid if we can. When we ! * borrow n_fid, just take a hold on the smb_fh_t, and don't ! * bump n_fidrefs as that tracks VFS-level opens. Similarly ! * in _tmpclose we just release the smb_fh_t, not n_fidrefs. */ int smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, ! smb_fh_t **fhpp) { struct smb_share *ssp = np->n_mount->smi_share; ! smb_fh_t *fhp = NULL; ! int error; /* Can we re-use n_fid? or must we open anew? */ mutex_enter(&np->r_statelock); if (np->n_fidrefs > 0 && ! (fhp = np->n_fid) != NULL && ! fhp->fh_vcgenid == ssp->ss_vcgenid && ! (fhp->fh_rights & rights) == rights) { ! smb_fh_hold(fhp); ! *fhpp = fhp; mutex_exit(&np->r_statelock); return (0); } mutex_exit(&np->r_statelock); + error = smb_fh_create(ssp, &fhp); + if (error != 0) + goto out; + /* re-open an existing file. */ error = smbfs_smb_ntcreatex(np, NULL, 0, 0, /* name nmlen xattr */ rights, SMB_EFA_NORMAL, NTCREATEX_SHARE_ACCESS_ALL, NTCREATEX_DISP_OPEN, 0, /* create options */ ! scrp, fhp, NULL, NULL); /* cr_act_p fa_p */ ! if (error != 0) ! goto out; ! fhp->fh_rights = rights; ! smb_fh_opened(fhp); ! *fhpp = fhp; ! fhp = NULL; + out: + if (fhp != NULL) + smb_fh_rele(fhp); + return (error); } ! /* ARGSUSED */ ! void ! smbfs_smb_tmpclose(struct smbnode *np, smb_fh_t *fhp) { ! smb_fh_rele(fhp); } int smbfs_smb_open( struct smbnode *np,
*** 1374,2324 **** const char *name, int nmlen, int xattr, uint32_t rights, struct smb_cred *scrp, ! uint16_t *fidp, ! uint32_t *rightsp, smbfattr_t *fap) { struct smb_share *ssp = np->n_mount->smi_share; ! struct smb_vc *vcp = SSTOVC(ssp); ! int accmode, error; ! uint16_t grantedmode; /* open an existing file */ - if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { error = smbfs_smb_ntcreatex(np, name, nmlen, xattr, rights, SMB_EFA_NORMAL, NTCREATEX_SHARE_ACCESS_ALL, NTCREATEX_DISP_OPEN, 0, /* create options */ ! scrp, fidp, ! NULL, fap); /* cr_act_p fa_p */ if (error != 0) ! return (error); ! *rightsp = rights; ! return (0); ! } ! accmode = smb_rights2mode(rights); ! error = smbfs_smb_oldopen(np, ! name, nmlen, xattr, accmode, scrp, ! fidp, &grantedmode, fap); ! if (error != 0) ! return (error); ! *rightsp = smb_mode2rights(grantedmode); ! (void) smbfs_smb_getfattr(np, fap, scrp); return (0); } ! int ! smbfs_smb_close(struct smb_share *ssp, uint16_t fid, ! struct timespec *mtime, struct smb_cred *scrp) { - int error; ! error = smb_smb_close(ssp, fid, mtime, scrp); ! ! /* ! * ENOTCONN isn't interesting - if the connection is closed, ! * so are all our FIDs - and EIO is also not interesting, ! * as it means a forced unmount was done. (was ENXIO) ! * Also ETIME, which means we sent the request but gave up ! * waiting before the response came back. ! * ! * Don't clog up the system log with warnings about these ! * uninteresting failures on closes. ! */ ! switch (error) { ! case ENOTCONN: ! case ENXIO: ! case EIO: ! case ETIME: ! error = 0; ! } ! return (error); } - static int - smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen, - int xattr, struct smb_cred *scrp, uint16_t *fidp) - { - struct smb_rq rq, *rqp = &rq; - struct smb_share *ssp = dnp->n_mount->smi_share; - struct mbchain *mbp; - struct mdchain *mdp; - struct timespec ctime; - uint8_t wc; - long tm; - int error; - uint16_t attr = SMB_FA_ARCHIVE; - - error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp); - if (error) - return (error); - smb_rq_getrequest(rqp, &mbp); - smb_rq_wstart(rqp); - if (name && *name == '.') - attr |= SMB_FA_HIDDEN; - mb_put_uint16le(mbp, attr); /* attributes */ - gethrestime(&ctime); - smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm); - mb_put_uint32le(mbp, tm); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - mb_put_uint8(mbp, SMB_DT_ASCII); - error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen, - xattr ? ':' : '\\'); - if (error) - goto out; - smb_rq_bend(rqp); - /* - * Don't want to risk missing a successful - * open response, or we could "leak" FIDs. - */ - rqp->sr_flags |= SMBR_NOINTR_RECV; - error = smb_rq_simple_timed(rqp, smb_timo_open); - if (error) - goto out; - - smb_rq_getreply(rqp, &mdp); - md_get_uint8(mdp, &wc); - if (wc != 1) { - error = EBADRPC; - goto out; - } - error = md_get_uint16le(mdp, fidp); - - out: - smb_rq_done(rqp); - return (error); - } - int smbfs_smb_create( struct smbnode *dnp, const char *name, int nmlen, int xattr, uint32_t disp, struct smb_cred *scrp, ! uint16_t *fidp) { struct smb_share *ssp = dnp->n_mount->smi_share; ! struct smb_vc *vcp = SSTOVC(ssp); uint32_t efa, rights; int error; /* * At present the only access we might need is to WRITE data, * and that only if we are creating a "symlink". When/if the * access needed gets more complex it should made a parameter * and be set upstream. */ - if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { rights = SA_RIGHT_FILE_WRITE_DATA; efa = SMB_EFA_NORMAL; if (!xattr && name && *name == '.') efa = SMB_EFA_HIDDEN; error = smbfs_smb_ntcreatex(dnp, name, nmlen, xattr, rights, efa, NTCREATEX_SHARE_ACCESS_ALL, disp, /* != NTCREATEX_DISP_OPEN */ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE, ! scrp, fidp, NULL, NULL); /* cr_act_p fa_p */ ! return (error); ! } ! error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp); return (error); } int ! smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name, ! int nmlen, int xattr) { - struct smb_rq rq, *rqp = &rq; struct smb_share *ssp = np->n_mount->smi_share; ! struct mbchain *mbp; ! int error; ! error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp); ! if (error) ! return (error); ! smb_rq_getrequest(rqp, &mbp); ! smb_rq_wstart(rqp); ! mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN); ! smb_rq_wend(rqp); ! smb_rq_bstart(rqp); ! mb_put_uint8(mbp, SMB_DT_ASCII); ! error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, nmlen, ! xattr ? ':' : '\\'); ! if (!error) { ! smb_rq_bend(rqp); ! error = smb_rq_simple(rqp); } - smb_rq_done(rqp); - return (error); - } - int - smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, - const char *tname, int tnmlen, struct smb_cred *scrp) - { - struct smb_rq rq, *rqp = &rq; - struct smb_share *ssp = src->n_mount->smi_share; - struct mbchain *mbp; - int error; - uint16_t fa; - char sep; - - error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp); - if (error) - return (error); - smb_rq_getrequest(rqp, &mbp); - smb_rq_wstart(rqp); - /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */ - fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0; - fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN; - mb_put_uint16le(mbp, fa); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - /* ! * When we're not adding any component name, the ! * passed sep is ignored, so just pass sep=0. */ ! mb_put_uint8(mbp, SMB_DT_ASCII); ! error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0); ! if (error) ! goto out; ! /* ! * After XATTR directories, separator is ":" ! */ ! sep = (src->n_flag & N_XATTR) ? ':' : '\\'; ! mb_put_uint8(mbp, SMB_DT_ASCII); ! error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep); ! if (error) ! goto out; ! ! smb_rq_bend(rqp); ! error = smb_rq_simple(rqp); ! out: ! smb_rq_done(rqp); ! return (error); } int - smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, - const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp) - { - struct smb_rq rq, *rqp = &rq; - struct smb_share *ssp = src->n_mount->smi_share; - struct mbchain *mbp; - int error; - - error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp); - if (error) - return (error); - smb_rq_getrequest(rqp, &mbp); - smb_rq_wstart(rqp); - mb_put_uint16le(mbp, SMB_TID_UNKNOWN); - mb_put_uint16le(mbp, 0x20); /* delete target file */ - mb_put_uint16le(mbp, flags); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - mb_put_uint8(mbp, SMB_DT_ASCII); - - error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, '\\'); - if (error) - goto out; - mb_put_uint8(mbp, SMB_DT_ASCII); - error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, '\\'); - if (error) - goto out; - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - - out: - smb_rq_done(rqp); - return (error); - } - - static int - smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len, - struct smb_cred *scrp) - { - struct smb_rq rq, *rqp = &rq; - struct smb_share *ssp = dnp->n_mount->smi_share; - struct mbchain *mbp; - int error; - - error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp); - if (error) - return (error); - smb_rq_getrequest(rqp, &mbp); - smb_rq_wstart(rqp); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - mb_put_uint8(mbp, SMB_DT_ASCII); - error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len, '\\'); - if (!error) { - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - } - smb_rq_done(rqp); - return (error); - } - - int smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen, struct smb_cred *scrp) { struct smb_share *ssp = dnp->n_mount->smi_share; ! struct smb_vc *vcp = SSTOVC(ssp); ! uint32_t rights; ! uint16_t fid; int error; /* * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but * just to be asking for something. The rights==0 case could * easily be broken on some old or unusual servers. */ - if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { rights = SA_RIGHT_FILE_READ_DATA; error = smbfs_smb_ntcreatex(dnp, name, nmlen, 0, /* xattr */ rights, SMB_EFA_DIRECTORY, NTCREATEX_SHARE_ACCESS_ALL, NTCREATEX_DISP_CREATE, NTCREATEX_OPTIONS_DIRECTORY, ! scrp, &fid, NULL, NULL); /* cr_act_p fa_p */ ! if (error) ! return (error); ! (void) smbfs_smb_close(ssp, fid, NULL, scrp); ! return (0); } - error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp); return (error); } - int - smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp) - { - struct smb_rq rq, *rqp = &rq; - struct smb_share *ssp = np->n_mount->smi_share; - struct mbchain *mbp; - int error; - - error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp); - if (error) - return (error); - smb_rq_getrequest(rqp, &mbp); - smb_rq_wstart(rqp); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - mb_put_uint8(mbp, SMB_DT_ASCII); - error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0, '\\'); - if (!error) { - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - } - smb_rq_done(rqp); - return (error); - } - - static int - smbfs_smb_search(struct smbfs_fctx *ctx) - { - struct smb_vc *vcp = SSTOVC(ctx->f_ssp); - struct smb_rq *rqp; - struct mbchain *mbp; - struct mdchain *mdp; - uint8_t wc, bt; - uint16_t ec, dlen, bc; - int maxent, error, iseof = 0; - - maxent = min(ctx->f_left, - (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN); - if (ctx->f_rq) { - smb_rq_done(ctx->f_rq); - ctx->f_rq = NULL; - } - error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, - ctx->f_scred, &rqp); - if (error) - return (error); - ctx->f_rq = rqp; - smb_rq_getrequest(rqp, &mbp); - smb_rq_wstart(rqp); - mb_put_uint16le(mbp, maxent); /* max entries to return */ - mb_put_uint16le(mbp, ctx->f_attrmask); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */ - if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { - error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, - ctx->f_wildcard, ctx->f_wclen, '\\'); - if (error) - return (error); - mb_put_uint8(mbp, SMB_DT_VARIABLE); - mb_put_uint16le(mbp, 0); /* context length */ - ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; - } else { - if (SMB_UNICODE_STRINGS(vcp)) { - mb_put_padbyte(mbp); - mb_put_uint8(mbp, 0); - } - mb_put_uint8(mbp, 0); - mb_put_uint8(mbp, SMB_DT_VARIABLE); - mb_put_uint16le(mbp, SMB_SKEYLEN); - mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); - } - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) { - error = 0; - iseof = 1; - ctx->f_flags |= SMBFS_RDD_EOF; - } else if (error) - return (error); - smb_rq_getreply(rqp, &mdp); - error = md_get_uint8(mdp, &wc); - if (error) - return (error); - if (wc != 1) - return (iseof ? ENOENT : EBADRPC); - md_get_uint16le(mdp, &ec); - md_get_uint16le(mdp, &bc); - md_get_uint8(mdp, &bt); - error = md_get_uint16le(mdp, &dlen); - if (error) - return (error); - if (ec == 0) - return (ENOENT); - ctx->f_ecnt = ec; - if (bc < 3) - return (EBADRPC); - bc -= 3; - if (bt != SMB_DT_VARIABLE) - return (EBADRPC); - if (dlen != bc || dlen % SMB_DENTRYLEN != 0) - return (EBADRPC); - return (0); - } - - - /*ARGSUSED*/ - static int - smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp, - const char *wildcard, int wclen, uint16_t attr) - { - - ctx->f_type = ft_LM1; - ctx->f_attrmask = attr; - if (wildcard) { - if (wclen == 1 && wildcard[0] == '*') { - ctx->f_wildcard = "*.*"; - ctx->f_wclen = 3; - } else { - ctx->f_wildcard = wildcard; - ctx->f_wclen = wclen; - } - } else { - ctx->f_wildcard = NULL; - ctx->f_wclen = 0; - } - ctx->f_name = (char *)ctx->f_fname; - ctx->f_namesz = 0; - return (0); - } - - static int - smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit) - { - struct mdchain *mdp; - struct smb_rq *rqp; - char *cp; - uint8_t battr; - uint16_t date, time; - uint32_t size; - int error; - struct timespec ts; - - if (ctx->f_ecnt == 0) { - if (ctx->f_flags & SMBFS_RDD_EOF) - return (ENOENT); - ctx->f_left = ctx->f_limit = limit; - gethrestime(&ts); - error = smbfs_smb_search(ctx); - if (error) - return (error); - } - rqp = ctx->f_rq; - smb_rq_getreply(rqp, &mdp); - md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM); - md_get_uint8(mdp, &battr); - md_get_uint16le(mdp, &time); - md_get_uint16le(mdp, &date); - md_get_uint32le(mdp, &size); - cp = ctx->f_name; - error = md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM); - cp[sizeof (ctx->f_fname) - 1] = 0; - cp += strlen(cp) - 1; - while (*cp == ' ' && cp >= ctx->f_name) - *cp-- = 0; - ctx->f_attr.fa_attr = battr; - smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz, - &ctx->f_attr.fa_mtime); - ctx->f_attr.fa_size = size; - ctx->f_nmlen = strlen(ctx->f_name); - ctx->f_ecnt--; - ctx->f_left--; - return (0); - } - - static int - smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx) - { - if (ctx->f_rq) - smb_rq_done(ctx->f_rq); - return (0); - } - /* ! * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect */ - static int - smbfs_smb_trans2find2(struct smbfs_fctx *ctx) - { - struct smb_t2rq *t2p; - struct smb_vc *vcp = SSTOVC(ctx->f_ssp); - struct mbchain *mbp; - struct mdchain *mdp; - uint16_t ecnt, eos, lno, flags; - int error; - - if (ctx->f_t2) { - smb_t2_done(ctx->f_t2); - ctx->f_t2 = NULL; - } - flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS; - if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) { - flags |= FIND2_CLOSE_AFTER_REQUEST; - ctx->f_flags |= SMBFS_RDD_NOCLOSE; - } - if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { - error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2, - ctx->f_scred, &t2p); - if (error) - return (error); - ctx->f_t2 = t2p; - mbp = &t2p->t2_tparam; - mb_init(mbp); - mb_put_uint16le(mbp, ctx->f_attrmask); - mb_put_uint16le(mbp, ctx->f_limit); - mb_put_uint16le(mbp, flags); - mb_put_uint16le(mbp, ctx->f_infolevel); - mb_put_uint32le(mbp, 0); - error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, - ctx->f_wildcard, ctx->f_wclen, '\\'); - if (error) - return (error); - } else { - error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2, - ctx->f_scred, &t2p); - if (error) - return (error); - ctx->f_t2 = t2p; - mbp = &t2p->t2_tparam; - mb_init(mbp); - mb_put_uint16le(mbp, ctx->f_Sid); - mb_put_uint16le(mbp, ctx->f_limit); - mb_put_uint16le(mbp, ctx->f_infolevel); - /* Send whatever resume key we received... */ - mb_put_uint32le(mbp, ctx->f_rkey); - mb_put_uint16le(mbp, flags); - /* ... and the resume name if we have one. */ - if (ctx->f_rname) { - /* resume file name */ - mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen, - MB_MSYSTEM); - } - /* Add trailing null - 1 byte if ASCII, 2 if Unicode */ - if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) - mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */ - mb_put_uint8(mbp, 0); - } - t2p->t2_maxpcount = 5 * 2; - t2p->t2_maxdcount = 0xF000; /* 64K less some overhead */ - error = smb_t2_request(t2p); - if (error) - return (error); - - /* - * This is the "resume name" we just sent. - * We want the new one (if any) that may be - * found in the response we just received and - * will now begin parsing. Free the old one - * now so we'll know if we found a new one. - */ - if (ctx->f_rname) { - kmem_free(ctx->f_rname, ctx->f_rnamelen); - ctx->f_rname = NULL; - ctx->f_rnamelen = 0; - } - - mdp = &t2p->t2_rparam; - if (ctx->f_flags & SMBFS_RDD_FINDFIRST) { - if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0) - goto nodata; - ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; - } - md_get_uint16le(mdp, &ecnt); /* entry count */ - md_get_uint16le(mdp, &eos); /* end of search */ - md_get_uint16le(mdp, NULL); /* EA err. off. */ - error = md_get_uint16le(mdp, &lno); /* last name off. */ - if (error != 0) - goto nodata; - - /* - * The "end of search" flag from an XP server sometimes - * comes back zero when the prior find_next returned exactly - * the number of entries requested. in which case we'd try again - * but the search has in fact been closed so an EBADF results. - * our circumvention is to check here for a zero entry count. - */ - ctx->f_ecnt = ecnt; - if (eos || ctx->f_ecnt == 0) - ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE; - if (ctx->f_ecnt == 0) - return (ENOENT); - - /* Last Name Off (LNO) is the entry with the resume name. */ - ctx->f_rnameofs = lno; - ctx->f_eofs = 0; - return (0); - - nodata: - /* - * Failed parsing the FindFirst or FindNext response. - * Force this directory listing closed, otherwise the - * calling process may hang in an infinite loop. - */ - ctx->f_ecnt = 0; /* Force closed. */ - ctx->f_flags |= SMBFS_RDD_EOF; - return (EIO); - } - - static int - smbfs_smb_findclose2(struct smbfs_fctx *ctx) - { - struct smb_rq rq, *rqp = &rq; - struct mbchain *mbp; - int error; - - error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, - ctx->f_scred); - if (error) - return (error); - smb_rq_getrequest(rqp, &mbp); - smb_rq_wstart(rqp); - mb_put_uint16le(mbp, ctx->f_Sid); - smb_rq_wend(rqp); - smb_rq_bstart(rqp); - smb_rq_bend(rqp); - /* Ditto comments at _smb_close */ - rqp->sr_flags |= SMBR_NOINTR_SEND; - error = smb_rq_simple(rqp); - smb_rq_done(rqp); - return (error); - } - - /*ARGSUSED*/ - static int - smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, - const char *wildcard, int wclen, uint16_t attr) - { - - ctx->f_type = ft_LM2; - ctx->f_namesz = SMB_MAXFNAMELEN + 1; - if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) - ctx->f_namesz *= 2; - ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP); - ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) - < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD : - SMB_FIND_BOTH_DIRECTORY_INFO; - ctx->f_attrmask = attr; - ctx->f_wildcard = wildcard; - ctx->f_wclen = wclen; - return (0); - } - - static int - smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit) - { - struct mdchain *mdp; - struct smb_t2rq *t2p; - char *cp; - uint8_t tb; - uint16_t date, time, wattr; - uint32_t size, next, dattr, resumekey = 0; - uint64_t llongint; - int error, svtz, cnt, fxsz, nmlen, recsz; - struct timespec ts; - - if (ctx->f_ecnt == 0) { - if (ctx->f_flags & SMBFS_RDD_EOF) - return (ENOENT); - ctx->f_left = ctx->f_limit = limit; - gethrestime(&ts); - error = smbfs_smb_trans2find2(ctx); - if (error) - return (error); - ctx->f_otws++; - } - t2p = ctx->f_t2; - mdp = &t2p->t2_rdata; - svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz; - switch (ctx->f_infolevel) { - case SMB_FIND_STANDARD: - next = 0; - fxsz = 0; - md_get_uint16le(mdp, &date); - md_get_uint16le(mdp, &time); /* creation time */ - smb_dos2unixtime(date, time, 0, svtz, - &ctx->f_attr.fa_createtime); - md_get_uint16le(mdp, &date); - md_get_uint16le(mdp, &time); /* access time */ - smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); - md_get_uint16le(mdp, &date); - md_get_uint16le(mdp, &time); /* modify time */ - smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); - md_get_uint32le(mdp, &size); - ctx->f_attr.fa_size = size; - md_get_uint32le(mdp, &size); /* allocation size */ - ctx->f_attr.fa_allocsz = size; - md_get_uint16le(mdp, &wattr); - ctx->f_attr.fa_attr = wattr; - error = md_get_uint8(mdp, &tb); - if (error) - goto nodata; - size = nmlen = tb; - fxsz = 23; - recsz = next = 24 + nmlen; /* docs misses zero byte @end */ - break; - case SMB_FIND_DIRECTORY_INFO: - case SMB_FIND_BOTH_DIRECTORY_INFO: - md_get_uint32le(mdp, &next); - md_get_uint32le(mdp, &resumekey); /* file index (resume key) */ - md_get_uint64le(mdp, &llongint); /* creation time */ - smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime); - md_get_uint64le(mdp, &llongint); - smb_time_NT2local(llongint, &ctx->f_attr.fa_atime); - md_get_uint64le(mdp, &llongint); - smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime); - md_get_uint64le(mdp, &llongint); - smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime); - md_get_uint64le(mdp, &llongint); /* file size */ - ctx->f_attr.fa_size = llongint; - md_get_uint64le(mdp, &llongint); /* alloc. size */ - ctx->f_attr.fa_allocsz = llongint; - md_get_uint32le(mdp, &dattr); /* ext. file attributes */ - ctx->f_attr.fa_attr = dattr; - error = md_get_uint32le(mdp, &size); /* name len */ - if (error) - goto nodata; - fxsz = 64; /* size ofinfo up to filename */ - if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) { - /* - * Skip EaSize(4 bytes), a byte of ShortNameLength, - * a reserved byte, and ShortName(8.3 means 24 bytes, - * as Leach defined it to always be Unicode) - */ - error = md_get_mem(mdp, NULL, 30, MB_MSYSTEM); - if (error) - goto nodata; - fxsz += 30; - } - recsz = next ? next : fxsz + size; - break; - default: - SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel); - return (EINVAL); - } - - if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) - nmlen = min(size, SMB_MAXFNAMELEN * 2); - else - nmlen = min(size, SMB_MAXFNAMELEN); - - /* Allocated f_name in findopen */ - ASSERT(nmlen < ctx->f_namesz); - cp = ctx->f_name; - - error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM); - if (error) - goto nodata; - if (next) { - /* How much data to skip? */ - cnt = next - nmlen - fxsz; - if (cnt < 0) { - SMBVDEBUG("out of sync\n"); - goto nodata; - } - if (cnt > 0) - md_get_mem(mdp, NULL, cnt, MB_MSYSTEM); - } - /* Don't count any trailing null in the name. */ - if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { - if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0) - nmlen -= 2; - } else { - if (nmlen && cp[nmlen - 1] == 0) - nmlen--; - } - if (nmlen == 0) - goto nodata; - - /* - * On a find-next we expect that the server will: - * 1) if the continue bit is set, use the server's offset, - * 2) else if the resume key is non-zero, use that offset, - * 3) else if the resume name is set, use that offset, - * 4) else use the server's idea of current offset. - * - * We always set the resume key flag. If the server returns - * a resume key then we should always send it back to them. - */ - ctx->f_rkey = resumekey; - - next = ctx->f_eofs + recsz; - if (ctx->f_rnameofs && - ctx->f_rnameofs >= ctx->f_eofs && - ctx->f_rnameofs < (int)next) { - /* - * This entry is the "resume name". - * Save it for the next request. - */ - if (ctx->f_rnamelen != nmlen) { - if (ctx->f_rname) - kmem_free(ctx->f_rname, ctx->f_rnamelen); - ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP); - ctx->f_rnamelen = nmlen; - } - bcopy(ctx->f_name, ctx->f_rname, nmlen); - } - ctx->f_nmlen = nmlen; - ctx->f_eofs = next; - ctx->f_ecnt--; - ctx->f_left--; - - smbfs_fname_tolocal(ctx); - return (0); - - nodata: - /* - * Something bad has happened and we ran out of data - * before we could parse all f_ecnt entries expected. - * Force this directory listing closed, otherwise the - * calling process may hang in an infinite loop. - */ - SMBVDEBUG("ran out of data\n"); - ctx->f_ecnt = 0; /* Force closed. */ - ctx->f_flags |= SMBFS_RDD_EOF; - return (EIO); - } - - static int - smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx) - { - int error = 0; - if (ctx->f_name) - kmem_free(ctx->f_name, ctx->f_namesz); - if (ctx->f_t2) - smb_t2_done(ctx->f_t2); - /* - * If SMBFS_RDD_FINDFIRST is still set, we were opened - * but never saw a findfirst, so we don't have any - * search handle to close. - */ - if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0) - error = smbfs_smb_findclose2(ctx); - return (error); - } - int smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen, int attr, struct smb_cred *scrp, struct smbfs_fctx **ctxpp) { struct smbfs_fctx *ctx; int error; ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP); ctx->f_flags = SMBFS_RDD_FINDFIRST; ctx->f_dnp = dnp; ctx->f_scred = scrp; ! ctx->f_ssp = dnp->n_mount->smi_share; if (dnp->n_flag & N_XATTR) { error = smbfs_xa_findopen(ctx, dnp, wild, wlen); goto out; } ! if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0) { ! error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr); } else { error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr); } out: ! if (error) ! (void) smbfs_smb_findclose(ctx, scrp); ! else *ctxpp = ctx; return (error); } int smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp) { ! int error; /* * Note: "limit" (maxcount) needs to fit in a short! */ if (limit > 0xffff) limit = 0xffff; ctx->f_scred = scrp; for (;;) { bzero(&ctx->f_attr, sizeof (ctx->f_attr)); switch (ctx->f_type) { ! case ft_LM1: ! error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit); break; case ft_LM2: ! error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit); break; case ft_XA: ! error = smbfs_xa_findnext(ctx, (uint16_t)limit); break; default: ASSERT(0); error = EINVAL; break; } if (error) ! return (error); /* * Skip "." or ".." - easy now that ctx->f_name * has already been converted to utf-8 format. */ if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || --- 404,651 ---- const char *name, int nmlen, int xattr, uint32_t rights, struct smb_cred *scrp, ! smb_fh_t **fhpp, smbfattr_t *fap) { struct smb_share *ssp = np->n_mount->smi_share; ! // struct smb_vc *vcp = SSTOVC(ssp); ! smb_fh_t *fhp = NULL; ! int error; + error = smb_fh_create(ssp, &fhp); + if (error != 0) + goto out; + /* open an existing file */ error = smbfs_smb_ntcreatex(np, name, nmlen, xattr, rights, SMB_EFA_NORMAL, NTCREATEX_SHARE_ACCESS_ALL, NTCREATEX_DISP_OPEN, 0, /* create options */ ! scrp, fhp, NULL, fap); if (error != 0) ! goto out; ! fhp->fh_rights = rights; ! smb_fh_opened(fhp); ! *fhpp = fhp; ! fhp = NULL; + out: + if (fhp != NULL) + smb_fh_rele(fhp); + return (0); } ! void ! smbfs_smb_close(smb_fh_t *fhp) { ! smb_fh_close(fhp); ! smb_fh_rele(fhp); } int smbfs_smb_create( struct smbnode *dnp, const char *name, int nmlen, int xattr, uint32_t disp, struct smb_cred *scrp, ! smb_fh_t **fhpp) { struct smb_share *ssp = dnp->n_mount->smi_share; ! // struct smb_vc *vcp = SSTOVC(ssp); ! smb_fh_t *fhp = NULL; uint32_t efa, rights; int error; + error = smb_fh_create(ssp, &fhp); + if (error != 0) + goto out; + /* * At present the only access we might need is to WRITE data, * and that only if we are creating a "symlink". When/if the * access needed gets more complex it should made a parameter * and be set upstream. */ rights = SA_RIGHT_FILE_WRITE_DATA; efa = SMB_EFA_NORMAL; if (!xattr && name && *name == '.') efa = SMB_EFA_HIDDEN; error = smbfs_smb_ntcreatex(dnp, name, nmlen, xattr, rights, efa, NTCREATEX_SHARE_ACCESS_ALL, disp, /* != NTCREATEX_DISP_OPEN */ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE, ! scrp, fhp, NULL, NULL); ! if (error != 0) ! goto out; ! fhp->fh_rights = rights; ! smb_fh_opened(fhp); ! *fhpp = fhp; ! fhp = NULL; ! ! out: ! if (fhp != NULL) ! smb_fh_rele(fhp); ! return (error); } int ! smbfs_smb_rename(struct smbnode *sdnp, struct smbnode *np, ! struct smbnode *tdnp, const char *tname, int tnlen, ! smb_fh_t *fhp, struct smb_cred *scrp) { struct smb_share *ssp = np->n_mount->smi_share; ! struct smb_vc *vcp = SSTOVC(ssp); ! int err; ! if (vcp->vc_flags & SMBV_SMB2) { ! err = smbfs_smb2_rename(np, tdnp, tname, tnlen, 0, ! &fhp->fh_fid2, scrp); ! return (err); } /* ! * SMB1 -- Want to use _t2rename if we can ! * (rename in same dir and cap pass-through) ! * Most SMB1 servers have cap pass-through. */ ! if (sdnp == tdnp && ! (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) != 0) { ! err = smbfs_smb1_t2rename(np, tname, tnlen, fhp->fh_fid1, scrp); ! } else { ! err = smbfs_smb1_oldrename(np, tdnp, tname, tnlen, scrp); ! } ! return (err); } int smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen, struct smb_cred *scrp) { + smb_fh_t tmp_fh; struct smb_share *ssp = dnp->n_mount->smi_share; ! uint32_t efa, rights; int error; /* + * Using a faked-up handle here to avoid the work of + * creating and destroying a real "conn obj". + */ + bzero(&tmp_fh, sizeof (tmp_fh)); + + /* * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but * just to be asking for something. The rights==0 case could * easily be broken on some old or unusual servers. */ rights = SA_RIGHT_FILE_READ_DATA; + efa = SMB_EFA_NORMAL; + if (name && *name == '.') + efa |= SMB_EFA_HIDDEN; error = smbfs_smb_ntcreatex(dnp, name, nmlen, 0, /* xattr */ rights, SMB_EFA_DIRECTORY, NTCREATEX_SHARE_ACCESS_ALL, NTCREATEX_DISP_CREATE, NTCREATEX_OPTIONS_DIRECTORY, ! scrp, &tmp_fh, NULL, NULL); ! if (error == 0) { ! (void) smb_smb_close(ssp, &tmp_fh, scrp); } return (error); } /* ! * Protocol-level directory open */ int smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen, int attr, struct smb_cred *scrp, struct smbfs_fctx **ctxpp) { + struct smb_share *ssp = dnp->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); struct smbfs_fctx *ctx; int error; ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP); ctx->f_flags = SMBFS_RDD_FINDFIRST; ctx->f_dnp = dnp; ctx->f_scred = scrp; ! ctx->f_ssp = ssp; if (dnp->n_flag & N_XATTR) { error = smbfs_xa_findopen(ctx, dnp, wild, wlen); goto out; } ! if (vcp->vc_flags & SMBV_SMB2) { ! error = smbfs_smb2_findopen(ctx, dnp, wild, wlen, attr); } else { error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr); } out: ! ctx->f_scred = NULL; ! if (error) { ! kmem_free(ctx, sizeof (*ctx)); ! } else { *ctxpp = ctx; + } + return (error); } int smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp) { ! int error = 0; ! uint16_t lim; /* * Note: "limit" (maxcount) needs to fit in a short! */ if (limit > 0xffff) limit = 0xffff; + lim = (uint16_t)limit; ctx->f_scred = scrp; for (;;) { bzero(&ctx->f_attr, sizeof (ctx->f_attr)); switch (ctx->f_type) { ! ! case ft_SMB2: ! error = smbfs_smb2_findnext(ctx, lim); break; case ft_LM2: ! error = smbfs_smb_findnextLM2(ctx, lim); break; case ft_XA: ! error = smbfs_xa_findnext(ctx, lim); break; default: ASSERT(0); error = EINVAL; break; } if (error) ! break; /* * Skip "." or ".." - easy now that ctx->f_name * has already been converted to utf-8 format. */ if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
*** 2325,2342 **** (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && ctx->f_name[1] == '.')) continue; break; } ! /* ! * Moved the smbfs_fname_tolocal(ctx) call into ! * the ..._findnext functions above. ! */ ! ctx->f_inum = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen); ! return (0); } int smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp) --- 652,673 ---- (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && ctx->f_name[1] == '.')) continue; break; } + ctx->f_scred = NULL; + if (error != 0) + return (error); ! ctx->f_inum = smbfs_getino(ctx->f_dnp, ! ctx->f_name, ctx->f_nmlen); ! #ifdef DEBUG ! SMBVDEBUG("findnext: (%s)\n", ctx->f_name); ! #endif ! ! return (error); } int smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
*** 2343,2362 **** { int error; ctx->f_scred = scrp; switch (ctx->f_type) { ! case ft_LM1: ! error = smbfs_smb_findcloseLM1(ctx); break; case ft_LM2: error = smbfs_smb_findcloseLM2(ctx); break; case ft_XA: error = smbfs_xa_findclose(ctx); break; } if (ctx->f_rname) kmem_free(ctx->f_rname, ctx->f_rnamelen); if (ctx->f_firstnm) kmem_free(ctx->f_firstnm, ctx->f_firstnmlen); kmem_free(ctx, sizeof (*ctx)); --- 674,697 ---- { int error; ctx->f_scred = scrp; switch (ctx->f_type) { ! case ft_SMB2: ! error = smbfs_smb2_findclose(ctx); break; case ft_LM2: error = smbfs_smb_findcloseLM2(ctx); break; case ft_XA: error = smbfs_xa_findclose(ctx); break; + default: + error = ENOSYS; + break; } + ctx->f_scred = NULL; if (ctx->f_rname) kmem_free(ctx->f_rname, ctx->f_rnamelen); if (ctx->f_firstnm) kmem_free(ctx->f_firstnm, ctx->f_firstnmlen); kmem_free(ctx, sizeof (*ctx));
*** 2392,2420 **** DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'"); return (EINVAL); } /* - * XXX: Should use _qpathinfo here instead. - * (if SMB_CAP_NT_SMBS) - */ - - /* * Shared lock for n_fid use (smb_flush). */ intr = dnp->n_mount->smi_flags & SMI_INT; if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr)) return (EINTR); - /* - * This hides a server bug observable in Win98: - * size changes may not show until a CLOSE or a FLUSH op - * XXX: Make this conditional on !NTSMBs - */ - error = smbfs_smb_flush(dnp, scrp); - if (error) - goto out; error = smbfs_smb_findopen(dnp, name, nmlen, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx); if (error) goto out; ctx->f_flags |= SMBFS_RDD_FINDSINGLE; --- 727,742 ----
*** 2444,2702 **** * * Note: On success, this fills in mdp->md_top, * which the caller should free. */ int ! smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid, ! struct smb_cred *scrp, uint32_t selector, ! mblk_t **res, uint32_t *reslen) { ! struct smb_ntrq *ntp; ! struct mbchain *mbp; ! struct mdchain *mdp; int error, len; - error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC, - scrp, &ntp); - if (error) - return (error); - - /* Parameters part */ - mbp = &ntp->nt_tparam; - mb_init(mbp); - mb_put_uint16le(mbp, fid); - mb_put_uint16le(mbp, 0); /* reserved */ - mb_put_uint32le(mbp, selector); - /* Data part (none) */ - - /* Max. returned parameters and data. */ - ntp->nt_maxpcount = 4; - ntp->nt_maxdcount = *reslen; - - error = smb_nt_request(ntp); - if (error && !(ntp->nt_flags & SMBT2_MOREDATA)) - goto done; *res = NULL; ! /* ! * if there's more data than we said we could receive, here ! * is where we pick up the length of it ! */ ! mdp = &ntp->nt_rparam; ! md_get_uint32le(mdp, reslen); ! if (error) ! goto done; /* * get the data part. */ ! mdp = &ntp->nt_rdata; ! if (mdp->md_top == NULL) { ! SMBVDEBUG("null md_top? fid 0x%x\n", fid); error = EBADRPC; goto done; } /* ! * The returned parameter SD_length should match ! * the length of the returned data. Unfortunately, ! * we have to work around server bugs here. */ ! len = m_fixhdr(mdp->md_top); ! if (len != *reslen) { ! SMBVDEBUG("len %d *reslen %d fid 0x%x\n", ! len, *reslen, fid); ! } ! ! /* ! * Actual data provided is < returned SD_length. ! * ! * The following "if (len < *reslen)" handles a Windows bug ! * observed when the underlying filesystem is FAT32. In that ! * case a 32 byte security descriptor comes back (S-1-1-0, ie ! * "Everyone") but the Parameter Block claims 44 is the length ! * of the security descriptor. (The Data Block length ! * claimed is 32. This server bug was reported against NT ! * first and I've personally observed it with W2K. ! */ if (len < *reslen) *reslen = len; - /* - * Actual data provided is > returned SD_length. - * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0) - * Narrow work-around for returned SD_length==0. - */ - if (len > *reslen) { - /* - * Increase *reslen, but carefully. - */ - if (*reslen == 0 && len <= ntp->nt_maxdcount) - *reslen = len; - } - error = md_get_mbuf(mdp, len, res); - done: if (error == 0 && *res == NULL) { ASSERT(*res); error = EBADRPC; } - smb_nt_done(ntp); return (error); } - #ifdef APPLE /* - * Wrapper for _getsd() compatible with darwin code. - */ - int - smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp, - uint32_t selector, struct ntsecdesc **res) - { - int error; - uint32_t len, olen; - struct mdchain *mdp, md_store; - struct mbuf *m; - - bzero(mdp, sizeof (*mdp)); - len = 500; /* "overlarge" values => server errors */ - again: - olen = len; - error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len); - /* - * Server may give us an error indicating that we - * need a larger data buffer to receive the SD, - * and the size we'll need. Use the given size, - * but only after a sanity check. - * - * XXX: Check for specific error values here? - * XXX: also ... && len <= MAX_RAW_SD_SIZE - */ - if (error && len > olen) - goto again; - - if (error) - return (error); - - mdp = &md_store; - md_initm(mdp, m); - MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK); - error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM); - md_done(mdp); - - return (error); - } - #endif /* APPLE */ - - /* * OTW function to Set a security descriptor (SD). * Caller data are carried in an mbchain_t. * * Note: This normally consumes mbp->mb_top, and clears * that pointer when it does. */ ! int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid, ! struct smb_cred *scrp, uint32_t selector, mblk_t **mp) { ! struct smb_ntrq *ntp; ! struct mbchain *mbp; int error; ! error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC, ! scrp, &ntp); ! if (error) ! return (error); ! ! /* Parameters part */ ! mbp = &ntp->nt_tparam; ! mb_init(mbp); ! mb_put_uint16le(mbp, fid); ! mb_put_uint16le(mbp, 0); /* reserved */ ! mb_put_uint32le(mbp, selector); ! ! /* Data part */ ! mbp = &ntp->nt_tdata; ! mb_initm(mbp, *mp); ! *mp = NULL; /* consumed */ ! ! /* No returned parameters or data. */ ! ntp->nt_maxpcount = 0; ! ntp->nt_maxdcount = 0; ! ! error = smb_nt_request(ntp); ! smb_nt_done(ntp); ! ! return (error); ! } ! ! #ifdef APPLE ! /* ! * This function builds the SD given the various parts. ! */ ! int ! smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp, ! uint32_t selector, uint16_t flags, struct ntsid *owner, ! struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl) ! { ! struct mbchain *mbp, mb_store; ! struct ntsecdesc ntsd; ! int error, off; ! ! /* ! * Build the SD as its own mbuf chain and pass it to ! * smbfs_smb_setsec_m() ! */ ! mbp = &mb_store; ! mb_init(mbp); ! bzero(&ntsd, sizeof (ntsd)); ! wset_sdrevision(&ntsd); ! /* ! * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN) ! * We set here only those bits we can be sure must be set. The rest ! * are up to the caller. In particular, the caller may intentionally ! * set an acl PRESENT bit while giving us a null pointer for the ! * acl - that sets a null acl, giving access to everyone. Note also ! * that the AUTO_INHERITED bits should probably always be set unless ! * the server is NT. ! */ ! flags |= SD_SELF_RELATIVE; ! off = sizeof (ntsd); ! if (owner) { ! wset_sdowneroff(&ntsd, off); ! off += sidlen(owner); } - if (group) { - wset_sdgroupoff(&ntsd, off); - off += sidlen(group); - } - if (sacl) { - flags |= SD_SACL_PRESENT; - wset_sdsacloff(&ntsd, off); - off += acllen(sacl); - } - if (dacl) { - flags |= SD_DACL_PRESENT; - wset_sddacloff(&ntsd, off); - } - wset_sdflags(&ntsd, flags); - mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM); - if (owner) - mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM); - if (group) - mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM); - if (sacl) - mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM); - if (dacl) - mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM); - /* - * Just pass the mbuf to _setsec_m - * It will clear mb_top if consumed. - */ - error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top); - mb_done(mbp); - return (error); } - - #endif /* APPLE */ --- 766,838 ---- * * Note: On success, this fills in mdp->md_top, * which the caller should free. */ int ! smbfs_smb_getsec(struct smb_share *ssp, smb_fh_t *fhp, ! uint32_t selector, mblk_t **res, uint32_t *reslen, ! struct smb_cred *scrp) { ! struct smb_vc *vcp = SSTOVC(ssp); int error, len; *res = NULL; ! if (vcp->vc_flags & SMBV_SMB2) { ! error = smbfs_smb2_getsec(ssp, &fhp->fh_fid2, ! selector, res, reslen, scrp); ! } else { ! error = smbfs_smb1_getsec(ssp, fhp->fh_fid1, ! selector, res, reslen, scrp); ! } /* * get the data part. */ ! if (*res == NULL) { error = EBADRPC; goto done; } /* ! * If message length is < returned SD_length, ! * correct *reslen (reduce it). It greater, ! * just ignore the extra data. */ ! len = m_fixhdr(*res); if (len < *reslen) *reslen = len; done: if (error == 0 && *res == NULL) { ASSERT(*res); error = EBADRPC; } return (error); } /* * OTW function to Set a security descriptor (SD). * Caller data are carried in an mbchain_t. * * Note: This normally consumes mbp->mb_top, and clears * that pointer when it does. */ ! int ! smbfs_smb_setsec(struct smb_share *ssp, smb_fh_t *fhp, ! uint32_t selector, mblk_t **mp, ! struct smb_cred *scrp) { ! struct smb_vc *vcp = SSTOVC(ssp); int error; ! if (vcp->vc_flags & SMBV_SMB2) { ! error = smbfs_smb2_setsec(ssp, &fhp->fh_fid2, ! selector, mp, scrp); ! } else { ! error = smbfs_smb1_setsec(ssp, fhp->fh_fid1, ! selector, mp, scrp); } return (error); }