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)

*** 31,43 **** * * $Id: smbfs_subr.c,v 1.18 2005/02/02 00:22:23 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> --- 31,44 ---- * * $Id: smbfs_subr.c,v 1.18 2005/02/02 00:22:23 lindak Exp $ */ /* * 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/time.h>
*** 45,54 **** --- 46,56 ---- #include <sys/sunddi.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>
*** 71,84 **** { int caseopt = SMB_CS_NONE; int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0; int error; ! if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0) ! caseopt |= SMB_CS_UPPER; ! ! if (unicode) { error = mb_put_padbyte(mbp); if (error) return (error); } --- 73,87 ---- { int caseopt = SMB_CS_NONE; int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0; int error; ! /* ! * SMB1 may need an alignment pad before (not SMB2) ! */ ! if (((vcp)->vc_flags & SMBV_SMB2) == 0 && ! ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0) { error = mb_put_padbyte(mbp); if (error) return (error); }
*** 120,134 **** error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt, NULL); if (error) return (error); } ! /* Put NULL termination. */ if (unicode) error = mb_put_uint16le(mbp, 0); else error = mb_put_uint8(mbp, 0); return (error); } /* --- 123,140 ---- error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt, NULL); if (error) return (error); } ! ! /* SMB1 wants NULL termination. */ ! if (((vcp)->vc_flags & SMBV_SMB2) == 0) { if (unicode) error = mb_put_uint16le(mbp, 0); else error = mb_put_uint8(mbp, 0); + } return (error); } /*
*** 180,185 **** --- 186,459 ---- * Conversion failed, but our caller does not * deal with errors here, so just put a "?". * Don't expect to ever see this. */ (void) strlcpy(ctx->f_name, "?", ctx->f_namesz); + } + + /* + * Decode a directory entry from OtW form into ctx->f_attr + * + * Caller already put some (wire-format) directory entries + * into ctx->f_mdchain and we expect to find one. + * + * Advancing correctly through the buffer can be tricky if one + * tries to add up the size of an entry as you go (which is how + * the darwin code this is derived from did it). The easiest way + * to correctly advance the position is to get a whole dirent + * into another mdchain (entry_mdc) based on NextEntryOffset, + * and then scan the data from that mdchain. On the last entry, + * we don't know the entire length, so just scan directly from + * what remains of the multi-entry buffer instead of trying to + * figure out the length to copy into a separate mdchain. + */ + int + smbfs_decode_dirent(struct smbfs_fctx *ctx) + { + struct mdchain entry_mdc; + struct mdchain *mdp = &ctx->f_mdchain; + size_t nmlen; + uint64_t llongint; + uint32_t nmsize, dattr; + uint32_t nextoff = 0; + int error; + + /* In case we error out... */ + ctx->f_nmlen = 0; + ctx->f_rkey = (uint32_t)-1; + bzero(&entry_mdc, sizeof (entry_mdc)); + + /* + * Setup mdp to point to an mbchain holding + * what should be a single directory entry. + */ + error = md_get_uint32le(mdp, &nextoff); + if (error != 0) + goto errout; + if (nextoff >= 4) { + /* + * More entries follow. Make a new mbchain + * holding just this one entry, then advance. + */ + mblk_t *m = NULL; + error = md_get_mbuf(mdp, nextoff - 4, &m); + if (error != 0) + goto errout; + md_initm(&entry_mdc, m); + mdp = &entry_mdc; + ctx->f_eofs += nextoff; + } else { + /* Scan directly from ctx->f_mdchain */ + ctx->f_eofs = ctx->f_left; + } + + /* + * Decode the fixed-size parts + */ + switch (ctx->f_infolevel) { + case FileFullDirectoryInformation: + case SMB_FIND_FULL_DIRECTORY_INFO: + md_get_uint32le(mdp, &ctx->f_rkey); /* resume key (idx) */ + 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, &nmsize); /* name size (otw) */ + if (error) + goto errout; + md_get_uint32le(mdp, NULL); /* Ea size */ + break; + + case FileStreamInformation: + error = md_get_uint32le(mdp, &nmsize); /* name size (otw) */ + 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; + /* + * Stream names start with a ':' that we want to skip. + * This is the easiest place to take care of that. + * Always unicode here. + */ + if (nmsize >= 2) { + struct mdchain save_mdc; + uint16_t wch; + save_mdc = *mdp; + md_get_uint16le(mdp, &wch); + if (wch == ':') { + /* OK, we skipped the ':' */ + nmsize -= 2; + } else { + SMBVDEBUG("No leading : in stream?\n"); + /* restore position */ + *mdp = save_mdc; + } + } + break; + + default: + SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel); + error = EINVAL; + goto errout; + } + + /* + * Get the filename, and convert to utf-8 + * Allocated f_name in findopen + */ + nmlen = ctx->f_namesz; + error = smb_get_dstring(mdp, SSTOVC(ctx->f_ssp), + ctx->f_name, &nmlen, nmsize); + if (error != 0) + goto errout; + ctx->f_nmlen = (int)nmlen; + md_done(&entry_mdc); + return (0); + + errout: + /* + * Something bad has happened and we ran out of data + * before we could parse all f_ecnt entries expected. + * Give up on the current buffer. + */ + SMBVDEBUG("ran out of data\n"); + ctx->f_eofs = ctx->f_left; + md_done(&entry_mdc); + return (error); + } + + /* + * Decode FileAllInformation + * + * The data is a concatenation of: + * FileBasicInformation + * FileStandardInformation + * FileInternalInformation + * FileEaInformation + * FilePositionInformation + * FileModeInformation + * FileAlignmentInformation + * FileNameInformation + */ + /*ARGSUSED*/ + int + smbfs_decode_file_all_info(struct smb_share *ssp, + struct mdchain *mdp, struct smbfattr *fap) + { + uint64_t llongint, lsize; + uint32_t dattr; + int error; + + /* + * This part is: FileBasicInformation + */ + + /* creation time */ + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, &fap->fa_createtime); + + /* last access time */ + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, &fap->fa_atime); + + /* last write time */ + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, &fap->fa_mtime); + + /* last change time */ + md_get_uint64le(mdp, &llongint); + smb_time_NT2local(llongint, &fap->fa_ctime); + + /* attributes */ + md_get_uint32le(mdp, &dattr); + fap->fa_attr = dattr; + + /* reserved */ + md_get_uint32le(mdp, NULL); + + /* + * This part is: FileStandardInformation + */ + + /* allocation size */ + md_get_uint64le(mdp, &lsize); + fap->fa_allocsz = lsize; + + /* File size */ + error = md_get_uint64le(mdp, &lsize); + fap->fa_size = lsize; + + /* + * There's more after this but we don't need it: + * Remainder of FileStandardInformation + * NumLlinks, DeletOnClose, IsDir, reserved. + * Then: + * FileInternalInformation + * FileEaInformation + * FilePositionInformation + * FileModeInformation + * FileAlignmentInformation + * FileNameInformation + */ + + return (error); + } + + /* + * Decode FileFsAttributeInformation + * + * ULONG FileSystemAttributes; + * LONG MaximumComponentNameLength; + * ULONG FileSystemNameLength; + * WCHAR FileSystemName[1]; + */ + int + smbfs_decode_fs_attr_info(struct smb_share *ssp, + struct mdchain *mdp, struct smb_fs_attr_info *fsa) + { + struct smb_vc *vcp = SSTOVC(ssp); + uint32_t nlen; + int error; + + 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(vcp)) { + uint16_t tmpbuf[FSTYPSZ]; + size_t tmplen, outlen; + + if (nlen > sizeof (tmpbuf)) + nlen = sizeof (tmpbuf); + error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM); + if (error != 0) + goto out; + tmplen = nlen / 2; /* UCS-2 chars */ + outlen = FSTYPSZ - 1; + error = 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); + } + + out: + return (error); }