#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/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
#include <smbfs/smbfs.h>
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
#if 0
int
smbfs_smb1_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;
ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
if (np->n_vcgenid != ssp->ss_vcgenid)
return (ESTALE);
if (op == SMB_LOCK_SHARED)
ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
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);
mb_put_uint8(mbp, 0);
mb_put_uint16le(mbp, 0);
mb_put_uint16le(mbp, np->n_fid);
mb_put_uint8(mbp, ltype);
mb_put_uint8(mbp, 0);
mb_put_uint32le(mbp, timeout);
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);
mb_put_uint32le(mbp, start >> 32);
mb_put_uint32le(mbp, start & 0xffffffff);
mb_put_uint32le(mbp, len >> 32);
mb_put_uint32le(mbp, len & 0xffffffff);
}
smb_rq_bend(rqp);
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);
}
#endif
int
smbfs_smb1_trans2_query(struct smbnode *np, uint16_t fid,
struct smbfattr *fap, struct smb_cred *scrp)
{
struct smb_share *ssp = np->n_mount->smi_share;
struct smb_vc *vcp = SSTOVC(ssp);
struct smb_t2rq *t2p;
struct mbchain *mbp;
struct mdchain *mdp;
uint16_t cmd;
uint16_t infolevel = SMB_QFILEINFO_ALL_INFO;
int error;
if (fid != SMB_FID_UNUSED)
cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
else
cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
if (error)
return (error);
mbp = &t2p->t2_tparam;
mb_init(mbp);
if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
mb_put_uint16le(mbp, fid);
mb_put_uint16le(mbp, infolevel);
if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
mb_put_uint32le(mbp, 0);
error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
if (error)
goto out;
}
t2p->t2_maxpcount = 2;
t2p->t2_maxdcount = vcp->vc_txmax;
error = smb_t2_request(t2p);
if (error)
goto out;
mdp = &t2p->t2_rdata;
error = smbfs_decode_file_all_info(ssp, mdp, fap);
out:
smb_t2_done(t2p);
return (error);
}
static int
smbfs_smb1_query_fs_info(struct smb_share *ssp, struct mdchain *info_mdp,
uint16_t level, struct smb_cred *scrp)
{
struct smb_t2rq *t2p;
struct mbchain *mbp;
struct mdchain *mdp;
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, level);
t2p->t2_maxpcount = 4;
t2p->t2_maxdcount = 1024;
error = smb_t2_request(t2p);
if (error)
goto out;
mdp = &t2p->t2_rdata;
*info_mdp = *mdp;
bzero(mdp, sizeof (*mdp));
out:
smb_t2_done(t2p);
return (error);
}
int
smbfs_smb1_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
struct smb_cred *scrp)
{
struct mdchain info_mdc, *mdp = &info_mdc;
int error;
bzero(mdp, sizeof (*mdp));
error = smbfs_smb1_query_fs_info(ssp, mdp,
SMB_QFS_ATTRIBUTE_INFO, scrp);
if (error)
goto out;
error = smbfs_decode_fs_attr_info(ssp, mdp, fsa);
out:
md_done(mdp);
return (error);
}
int
smbfs_smb1_statfs(struct smb_share *ssp,
struct smb_fs_size_info *info,
struct smb_cred *scrp)
{
struct mdchain info_mdc, *mdp = &info_mdc;
struct smb_vc *vcp = SSTOVC(ssp);
uint16_t level;
int error;
bzero(mdp, sizeof (*mdp));
if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
level = SMB_QFS_FULL_SIZE_INFORMATION;
else
level = SMB_QFS_SIZE_INFO;
error = smbfs_smb1_query_fs_info(ssp, mdp, level, scrp);
if (error)
goto out;
md_get_uint64le(mdp, &info->total_units);
md_get_uint64le(mdp, &info->caller_avail);
if (level == SMB_QFS_FULL_SIZE_INFORMATION)
md_get_uint64le(mdp, &info->actual_avail);
else
info->actual_avail = info->caller_avail;
md_get_uint32le(mdp, &info->sect_per_unit);
error = md_get_uint32le(mdp, &info->bytes_per_sect);
out:
md_done(mdp);
return (error);
}
int
smbfs_smb1_flush(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp)
{
struct smb_rq rq, *rqp = &rq;
struct mbchain *mbp;
int error;
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, fid);
smb_rq_wend(rqp);
smb_rq_bstart(rqp);
smb_rq_bend(rqp);
error = smb_rq_simple(rqp);
smb_rq_done(rqp);
return (error);
}
static int
smbfs_smb1_setinfo_file(struct smb_share *ssp, uint16_t fid,
struct mbchain *info_mbp, uint16_t level, struct smb_cred *scrp)
{
struct smb_t2rq *t2p = NULL;
struct mbchain *mbp;
uint16_t cmd = SMB_TRANS2_SET_FILE_INFORMATION;
int error;
ASSERT(fid != SMB_FID_UNUSED);
error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
if (error)
return (error);
mbp = &t2p->t2_tparam;
mb_init(mbp);
mb_put_uint16le(mbp, fid);
mb_put_uint16le(mbp, level);
mb_put_uint16le(mbp, 0);
mbp = &t2p->t2_tdata;
mb_init(mbp);
error = mb_put_mbchain(mbp, info_mbp);
if (error)
goto out;
t2p->t2_maxpcount = 2;
t2p->t2_maxdcount = 0;
error = smb_t2_request(t2p);
out:
smb_t2_done(t2p);
return (error);
}
int
smbfs_smb1_seteof(struct smb_share *ssp, uint16_t fid,
uint64_t newsize, struct smb_cred *scrp)
{
struct mbchain data_mb, *mbp = &data_mb;
uint16_t level;
int error;
if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
level = SMB_SFILEINFO_END_OF_FILE_INFORMATION;
else
level = SMB_SFILEINFO_END_OF_FILE_INFO;
mb_init(mbp);
error = mb_put_uint64le(mbp, newsize);
if (error)
goto out;
error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
out:
mb_done(mbp);
return (error);
}
int
smbfs_smb1_setdisp(struct smb_share *ssp, uint16_t fid,
uint8_t newdisp, struct smb_cred *scrp)
{
struct mbchain data_mb, *mbp = &data_mb;
uint16_t level;
int error;
if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
else
level = SMB_SFILEINFO_DISPOSITION_INFO;
mb_init(mbp);
error = mb_put_uint8(mbp, newdisp);
if (error)
goto out;
error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
out:
mb_done(mbp);
return (error);
}
int
smbfs_smb1_setfattr(struct smb_share *ssp, uint16_t fid,
struct mbchain *mbp, struct smb_cred *scrp)
{
uint16_t level;
int error;
if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
level = SMB_SFILEINFO_BASIC_INFORMATION;
else
level = SMB_SFILEINFO_BASIC_INFO;
error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
return (error);
}
int
smbfs_smb1_t2rename(struct smbnode *np,
const char *tname, int tnlen,
uint16_t fid, struct smb_cred *scrp)
{
struct smb_share *ssp = np->n_mount->smi_share;
struct mbchain data_mb, *mbp = &data_mb;
struct smb_vc *vcp = SSTOVC(ssp);
uint32_t *name_lenp;
uint16_t level = SMB_SFILEINFO_RENAME_INFORMATION;
int base, len;
int error;
mb_init(mbp);
mb_put_uint32le(mbp, 0);
mb_put_uint32le(mbp, 0);
name_lenp = mb_reserve(mbp, 4);
base = mbp->mb_count;
error = smb_put_dmem(mbp, vcp, tname, tnlen, SMB_CS_NONE, NULL);
if (error)
goto out;
len = mbp->mb_count - base;
*name_lenp = htolel(len);
error = smbfs_smb1_setinfo_file(ssp, fid, mbp, level, scrp);
out:
mb_done(mbp);
return (error);
}
int
smbfs_smb1_oldrename(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);
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);
mb_put_uint8(mbp, SMB_DT_ASCII);
error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0);
if (error)
goto out;
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);
}
static int
smbfs_smb1_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;
uint16_t amask, limit;
int error;
limit = ctx->f_limit;
amask = (uint16_t)ctx->f_attrmask;
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, amask);
mb_put_uint16le(mbp, 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, limit);
mb_put_uint16le(mbp, ctx->f_infolevel);
mb_put_uint32le(mbp, ctx->f_rkey);
mb_put_uint16le(mbp, flags);
if (ctx->f_rname) {
mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
MB_MSYSTEM);
}
if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
mb_put_uint8(mbp, 0);
mb_put_uint8(mbp, 0);
}
t2p->t2_maxpcount = 5 * 2;
t2p->t2_maxdcount = 0xF000;
error = smb_t2_request(t2p);
if (error)
return (error);
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);
md_get_uint16le(mdp, &eos);
md_get_uint16le(mdp, NULL);
error = md_get_uint16le(mdp, &lno);
if (error != 0)
goto nodata;
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);
ctx->f_rnameofs = lno;
ctx->f_eofs = 0;
mdp = &t2p->t2_rdata;
md_done(&ctx->f_mdchain);
ctx->f_mdchain = *mdp;
ctx->f_left = m_fixhdr(mdp->md_top);
bzero(mdp, sizeof (*mdp));
return (0);
nodata:
ctx->f_ecnt = 0;
ctx->f_flags |= SMBFS_RDD_EOF;
return (EIO);
}
static int
smbfs_smb1_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);
rqp->sr_flags |= SMBR_NOINTR_SEND;
error = smb_rq_simple(rqp);
smb_rq_done(rqp);
return (error);
}
int
smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
const char *wildcard, int wclen, uint32_t attr)
{
ctx->f_type = ft_LM2;
ctx->f_namesz = SMB_MAXFNAMELEN + 1;
ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
ctx->f_infolevel = SMB_FIND_FULL_DIRECTORY_INFO;
ctx->f_attrmask = attr;
ctx->f_wildcard = wildcard;
ctx->f_wclen = wclen;
return (0);
}
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);
md_done(&ctx->f_mdchain);
if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
error = smbfs_smb1_findclose2(ctx);
return (error);
}
int
smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
{
int error;
if ((ctx->f_eofs + 8) > ctx->f_left) {
if (ctx->f_flags & SMBFS_RDD_EOF)
return (ENOENT);
ctx->f_limit = limit;
error = smbfs_smb1_trans2find2(ctx);
if (error)
return (error);
ctx->f_otws++;
}
error = smbfs_decode_dirent(ctx);
return (error);
}
int
smbfs_smb1_get_streaminfo(smbnode_t *np, struct mdchain *mdp,
struct smb_cred *scrp)
{
smb_share_t *ssp = np->n_mount->smi_share;
struct smb_vc *vcp = SSTOVC(ssp);
struct smb_t2rq *t2p = NULL;
struct mbchain *mbp;
mblk_t *m;
uint16_t cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
int error;
error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
if (error)
return (error);
mbp = &t2p->t2_tparam;
(void) mb_init(mbp);
(void) mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
(void) mb_put_uint32le(mbp, 0);
error = smbfs_fullpath(mbp, vcp, np, NULL, 0, 0);
if (error)
goto out;
t2p->t2_maxpcount = 2;
t2p->t2_maxdcount = INT16_MAX;
error = smb_t2_request(t2p);
if (error) {
if (t2p->t2_sr_error == NT_STATUS_INVALID_PARAMETER)
error = ENOTSUP;
goto out;
}
m = t2p->t2_rdata.md_top;
if (m == NULL) {
error = EBADRPC;
goto out;
}
t2p->t2_rdata.md_top = NULL;
md_initm(mdp, m);
out:
smb_t2_done(t2p);
return (error);
}
int
smbfs_smb1_getsec(struct smb_share *ssp, uint16_t fid,
uint32_t selector, mblk_t **res, uint32_t *reslen,
struct smb_cred *scrp)
{
struct smb_ntrq *ntp;
struct mbchain *mbp;
struct mdchain *mdp;
uint32_t dlen;
int error;
*res = NULL;
error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
scrp, &ntp);
if (error)
return (error);
mbp = &ntp->nt_tparam;
mb_init(mbp);
mb_put_uint16le(mbp, fid);
mb_put_uint16le(mbp, 0);
mb_put_uint32le(mbp, selector);
ntp->nt_maxpcount = 4;
ntp->nt_maxdcount = *reslen;
error = smb_nt_request(ntp);
if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
goto done;
mdp = &ntp->nt_rparam;
error = md_get_uint32le(mdp, &dlen);
if (error)
goto done;
*reslen = dlen;
if (dlen == 0) {
error = EBADRPC;
goto done;
}
mdp = &ntp->nt_rdata;
error = md_get_mbuf(mdp, dlen, res);
done:
if (error == 0 && *res == NULL) {
ASSERT(*res);
error = EBADRPC;
}
smb_nt_done(ntp);
return (error);
}
int
smbfs_smb1_setsec(struct smb_share *ssp, uint16_t fid,
uint32_t selector, mblk_t **mp, struct smb_cred *scrp)
{
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);
mbp = &ntp->nt_tparam;
mb_init(mbp);
mb_put_uint16le(mbp, fid);
mb_put_uint16le(mbp, 0);
mb_put_uint32le(mbp, selector);
mbp = &ntp->nt_tdata;
mb_initm(mbp, *mp);
*mp = NULL;
ntp->nt_maxpcount = 0;
ntp->nt_maxdcount = 0;
error = smb_nt_request(ntp);
smb_nt_done(ntp);
return (error);
}