Import kernel part of SMB/CIFS requester.
Add smbfs(CIFS) filesystem. Userland part will be in the ports tree for a while. Obtained from: smbfs-1.3.7-dev package.
This commit is contained in:
parent
43d97995d8
commit
681a5bbef2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=75374
@ -121,6 +121,12 @@ dev/syscons/scvidctl.c optional sc
|
|||||||
dev/syscons/scvtb.c optional sc
|
dev/syscons/scvtb.c optional sc
|
||||||
dev/syscons/syscons.c optional sc
|
dev/syscons/syscons.c optional sc
|
||||||
dev/syscons/sysmouse.c optional sc
|
dev/syscons/sysmouse.c optional sc
|
||||||
|
fs/smbfs/smbfs_io.c optional smbfs
|
||||||
|
fs/smbfs/smbfs_node.c optional smbfs
|
||||||
|
fs/smbfs/smbfs_smb.c optional smbfs
|
||||||
|
fs/smbfs/smbfs_subr.c optional smbfs
|
||||||
|
fs/smbfs/smbfs_vfsops.c optional smbfs
|
||||||
|
fs/smbfs/smbfs_vnops.c optional smbfs
|
||||||
gnu/i386/fpemul/div_small.s optional gpl_math_emulate
|
gnu/i386/fpemul/div_small.s optional gpl_math_emulate
|
||||||
gnu/i386/fpemul/errors.c optional gpl_math_emulate
|
gnu/i386/fpemul/errors.c optional gpl_math_emulate
|
||||||
gnu/i386/fpemul/fpu_arith.c optional gpl_math_emulate
|
gnu/i386/fpemul/fpu_arith.c optional gpl_math_emulate
|
||||||
@ -362,6 +368,7 @@ isa/vga_isa.c optional vga
|
|||||||
kern/imgact_aout.c standard
|
kern/imgact_aout.c standard
|
||||||
kern/imgact_gzip.c optional gzip
|
kern/imgact_gzip.c optional gzip
|
||||||
kern/link_aout.c standard
|
kern/link_aout.c standard
|
||||||
|
kern/md4c.c optional netsmb
|
||||||
kern/subr_diskmbr.c standard
|
kern/subr_diskmbr.c standard
|
||||||
libkern/divdi3.c standard
|
libkern/divdi3.c standard
|
||||||
libkern/moddi3.c standard
|
libkern/moddi3.c standard
|
||||||
@ -369,3 +376,12 @@ libkern/qdivrem.c standard
|
|||||||
libkern/ucmpdi2.c standard
|
libkern/ucmpdi2.c standard
|
||||||
libkern/udivdi3.c standard
|
libkern/udivdi3.c standard
|
||||||
libkern/umoddi3.c standard
|
libkern/umoddi3.c standard
|
||||||
|
netsmb/smb_conn.c optional netsmb
|
||||||
|
netsmb/smb_crypt.c optional netsmb
|
||||||
|
netsmb/smb_dev.c optional netsmb
|
||||||
|
netsmb/smb_iod.c optional netsmb
|
||||||
|
netsmb/smb_rq.c optional netsmb
|
||||||
|
netsmb/smb_smb.c optional netsmb
|
||||||
|
netsmb/smb_subr.c optional netsmb
|
||||||
|
netsmb/smb_trantcp.c optional netsmb
|
||||||
|
netsmb/smb_usr.c optional netsmb
|
||||||
|
@ -198,6 +198,13 @@ NDGBPORTS opt_dgb.h
|
|||||||
DEV_NPX opt_npx.h
|
DEV_NPX opt_npx.h
|
||||||
DEV_APM opt_apm.h
|
DEV_APM opt_apm.h
|
||||||
|
|
||||||
|
# SMB/CIFS requester
|
||||||
|
NETSMB
|
||||||
|
NETSMBCRYPTO
|
||||||
|
|
||||||
|
# SMB/CIFS filesystem
|
||||||
|
SMBFS
|
||||||
|
|
||||||
# -------------------------------
|
# -------------------------------
|
||||||
# EOF
|
# EOF
|
||||||
# -------------------------------
|
# -------------------------------
|
||||||
|
112
sys/fs/smbfs/smbfs.h
Normal file
112
sys/fs/smbfs/smbfs.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001, Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#ifndef _SMBFS_SMBFS_H_
|
||||||
|
#define _SMBFS_SMBFS_H_
|
||||||
|
|
||||||
|
#define VT_SMBFS 24
|
||||||
|
|
||||||
|
#define SMBFS_VERMAJ 1
|
||||||
|
#define SMBFS_VERMIN 1012
|
||||||
|
#define SMBFS_VERSION (SMBFS_VERMAJ*100000 + SMBFS_VERMIN)
|
||||||
|
#define SMBFS_VFSNAME "smbfs"
|
||||||
|
|
||||||
|
/* Values for flags */
|
||||||
|
#define SMBFS_MOUNT_SOFT 0x0001
|
||||||
|
#define SMBFS_MOUNT_INTR 0x0002
|
||||||
|
#define SMBFS_MOUNT_STRONG 0x0004
|
||||||
|
#define SMBFS_MOUNT_HAVE_NLS 0x0008
|
||||||
|
#define SMBFS_MOUNT_NO_LONG 0x0010
|
||||||
|
|
||||||
|
#define SMBFS_MAXPATHCOMP 256 /* maximum number of path components */
|
||||||
|
|
||||||
|
|
||||||
|
/* Layout of the mount control block for a netware file system. */
|
||||||
|
struct smbfs_args {
|
||||||
|
int version;
|
||||||
|
int dev;
|
||||||
|
u_int flags;
|
||||||
|
char mount_point[MAXPATHLEN];
|
||||||
|
u_char root_path[512+1];
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
mode_t file_mode;
|
||||||
|
mode_t dir_mode;
|
||||||
|
int caseopt;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
|
||||||
|
#ifdef MALLOC_DECLARE
|
||||||
|
MALLOC_DECLARE(M_SMBFSMNT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef VI_LOCK
|
||||||
|
#define VI_LOCK(vp) smb_sl_lock(&(vp)->v_interlock)
|
||||||
|
#define VI_UNLOCK(vp) smb_sl_unlock(&(vp)->v_interlock)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct smbnode;
|
||||||
|
struct smb_share;
|
||||||
|
struct u_cred;
|
||||||
|
struct vop_ioctl_args;
|
||||||
|
struct buf;
|
||||||
|
|
||||||
|
struct smbmount {
|
||||||
|
struct smbfs_args sm_args;
|
||||||
|
struct mount * sm_mp;
|
||||||
|
struct smbnode * sm_root;
|
||||||
|
struct ucred * sm_owner;
|
||||||
|
int sm_flags;
|
||||||
|
long sm_nextino;
|
||||||
|
struct smb_share * sm_share;
|
||||||
|
/* struct simplelock sm_npslock;*/
|
||||||
|
struct smbnode * sm_npstack[SMBFS_MAXPATHCOMP];
|
||||||
|
int sm_caseopt;
|
||||||
|
struct lock sm_hashlock;
|
||||||
|
LIST_HEAD(smbnode_hashhead, smbnode) *sm_hash;
|
||||||
|
u_long sm_hashlen;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define VFSTOSMBFS(mp) ((struct smbmount *)((mp)->mnt_data))
|
||||||
|
#define SMBFSTOVFS(smp) ((struct mount *)((smp)->sm_mp))
|
||||||
|
#define VTOVFS(vp) ((vp)->v_mount)
|
||||||
|
#define VTOSMBFS(vp) (VFSTOSMBFS(VTOVFS(vp)))
|
||||||
|
|
||||||
|
int smbfs_ioctl(struct vop_ioctl_args *ap);
|
||||||
|
int smbfs_doio(struct buf *bp, struct ucred *cr, struct proc *p);
|
||||||
|
int smbfs_vinvalbuf(struct vnode *vp, int flags, struct ucred *cred,
|
||||||
|
struct proc *p, int intrflg);
|
||||||
|
#endif /* KERNEL */
|
||||||
|
|
||||||
|
#endif /* _SMBFS_SMBFS_H_ */
|
672
sys/fs/smbfs/smbfs_io.c
Normal file
672
sys/fs/smbfs/smbfs_io.c
Normal file
@ -0,0 +1,672 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001, Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/resourcevar.h> /* defines plimit structure in proc struct */
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <sys/bio.h>
|
||||||
|
#include <sys/buf.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/namei.h>
|
||||||
|
#include <sys/vnode.h>
|
||||||
|
#include <sys/dirent.h>
|
||||||
|
#include <sys/signalvar.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
|
#include <vm/vm.h>
|
||||||
|
#if __FreeBSD_version < 400000
|
||||||
|
#include <vm/vm_prot.h>
|
||||||
|
#endif
|
||||||
|
#include <vm/vm_page.h>
|
||||||
|
#include <vm/vm_extern.h>
|
||||||
|
#include <vm/vm_object.h>
|
||||||
|
#include <vm/vm_pager.h>
|
||||||
|
#include <vm/vnode_pager.h>
|
||||||
|
/*
|
||||||
|
#include <sys/ioccom.h>
|
||||||
|
*/
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
|
||||||
|
#include <fs/smbfs/smbfs.h>
|
||||||
|
#include <fs/smbfs/smbfs_node.h>
|
||||||
|
#include <fs/smbfs/smbfs_subr.h>
|
||||||
|
|
||||||
|
/*#define SMBFS_RWGENERIC*/
|
||||||
|
|
||||||
|
extern int smbfs_pbuf_freecnt;
|
||||||
|
|
||||||
|
static int smbfs_fastlookup = 1;
|
||||||
|
|
||||||
|
extern struct linker_set sysctl_vfs_smbfs;
|
||||||
|
|
||||||
|
SYSCTL_DECL(_vfs_smbfs);
|
||||||
|
SYSCTL_INT(_vfs_smbfs, OID_AUTO, fastlookup, CTLFLAG_RW, &smbfs_fastlookup, 0, "");
|
||||||
|
|
||||||
|
|
||||||
|
#define DE_SIZE (sizeof(struct dirent))
|
||||||
|
|
||||||
|
static int
|
||||||
|
smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
|
||||||
|
{
|
||||||
|
struct dirent de;
|
||||||
|
struct componentname cn;
|
||||||
|
struct smb_cred scred;
|
||||||
|
struct smbfs_fctx *ctx;
|
||||||
|
struct vnode *newvp;
|
||||||
|
struct smbnode *np = VTOSMB(vp);
|
||||||
|
int error/*, *eofflag = ap->a_eofflag*/;
|
||||||
|
long offset, limit;
|
||||||
|
|
||||||
|
np = VTOSMB(vp);
|
||||||
|
SMBVDEBUG("dirname='%s'\n", np->n_name);
|
||||||
|
smb_makescred(&scred, uio->uio_procp, cred);
|
||||||
|
offset = uio->uio_offset / DE_SIZE; /* offset in the directory */
|
||||||
|
limit = uio->uio_resid / DE_SIZE;
|
||||||
|
if (uio->uio_resid < DE_SIZE || uio->uio_offset < 0)
|
||||||
|
return EINVAL;
|
||||||
|
while (limit && offset < 2) {
|
||||||
|
limit--;
|
||||||
|
bzero((caddr_t)&de, DE_SIZE);
|
||||||
|
de.d_reclen = DE_SIZE;
|
||||||
|
de.d_fileno = (offset == 0) ? np->n_ino :
|
||||||
|
(np->n_parent ? np->n_parent->n_ino : 2);
|
||||||
|
if (de.d_fileno == 0)
|
||||||
|
de.d_fileno = 0x7ffffffd + offset;
|
||||||
|
de.d_namlen = offset + 1;
|
||||||
|
de.d_name[0] = '.';
|
||||||
|
de.d_name[1] = '.';
|
||||||
|
de.d_name[offset + 1] = '\0';
|
||||||
|
de.d_type = DT_DIR;
|
||||||
|
error = uiomove((caddr_t)&de, DE_SIZE, uio);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
offset++;
|
||||||
|
uio->uio_offset += DE_SIZE;
|
||||||
|
}
|
||||||
|
if (limit == 0)
|
||||||
|
return 0;
|
||||||
|
if (offset != np->n_dirofs || np->n_dirseq == NULL) {
|
||||||
|
SMBVDEBUG("Reopening search %ld:%ld\n", offset, np->n_dirofs);
|
||||||
|
if (np->n_dirseq) {
|
||||||
|
smbfs_findclose(np->n_dirseq, &scred);
|
||||||
|
np->n_dirseq = NULL;
|
||||||
|
}
|
||||||
|
np->n_dirofs = 2;
|
||||||
|
error = smbfs_findopen(np, "*", 1,
|
||||||
|
SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
|
||||||
|
&scred, &ctx);
|
||||||
|
if (error) {
|
||||||
|
SMBVDEBUG("can not open search, error = %d", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
np->n_dirseq = ctx;
|
||||||
|
} else
|
||||||
|
ctx = np->n_dirseq;
|
||||||
|
while (np->n_dirofs < offset) {
|
||||||
|
error = smbfs_findnext(ctx, offset - np->n_dirofs++, &scred);
|
||||||
|
if (error) {
|
||||||
|
smbfs_findclose(np->n_dirseq, &scred);
|
||||||
|
np->n_dirseq = NULL;
|
||||||
|
return error == ENOENT ? 0 : error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error = 0;
|
||||||
|
for (; limit; limit--, offset++) {
|
||||||
|
error = smbfs_findnext(ctx, limit, &scred);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
np->n_dirofs++;
|
||||||
|
bzero((caddr_t)&de, DE_SIZE);
|
||||||
|
de.d_reclen = DE_SIZE;
|
||||||
|
de.d_fileno = ctx->f_attr.fa_ino;
|
||||||
|
de.d_type = (ctx->f_attr.fa_attr & SMB_FA_DIR) ? DT_DIR : DT_REG;
|
||||||
|
de.d_namlen = ctx->f_nmlen;
|
||||||
|
bcopy(ctx->f_name, de.d_name, de.d_namlen);
|
||||||
|
de.d_name[de.d_namlen] = '\0';
|
||||||
|
if (smbfs_fastlookup) {
|
||||||
|
error = smbfs_nget(vp->v_mount, vp, ctx->f_name,
|
||||||
|
ctx->f_nmlen, &ctx->f_attr, &newvp);
|
||||||
|
if (!error) {
|
||||||
|
cn.cn_nameptr = de.d_name;
|
||||||
|
cn.cn_namelen = de.d_namlen;
|
||||||
|
cache_enter(vp, newvp, &cn);
|
||||||
|
vput(newvp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error = uiomove((caddr_t)&de, DE_SIZE, uio);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (error == ENOENT)
|
||||||
|
error = 0;
|
||||||
|
uio->uio_offset = offset * DE_SIZE;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred)
|
||||||
|
{
|
||||||
|
struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
|
||||||
|
struct smbnode *np = VTOSMB(vp);
|
||||||
|
struct proc *p;
|
||||||
|
struct vattr vattr;
|
||||||
|
struct smb_cred scred;
|
||||||
|
int error, lks;
|
||||||
|
|
||||||
|
if (vp->v_type != VREG && vp->v_type != VDIR) {
|
||||||
|
SMBFSERR("vn types other than VREG or VDIR are unsupported !\n");
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
if (uiop->uio_resid == 0)
|
||||||
|
return 0;
|
||||||
|
if (uiop->uio_offset < 0)
|
||||||
|
return EINVAL;
|
||||||
|
/* if (uiop->uio_offset + uiop->uio_resid > smp->nm_maxfilesize)
|
||||||
|
return EFBIG;*/
|
||||||
|
p = uiop->uio_procp;
|
||||||
|
if (vp->v_type == VDIR) {
|
||||||
|
lks = LK_EXCLUSIVE;/*lockstatus(&vp->v_lock, p);*/
|
||||||
|
if (lks == LK_SHARED)
|
||||||
|
vn_lock(vp, LK_UPGRADE | LK_RETRY, p);
|
||||||
|
error = smbfs_readvdir(vp, uiop, cred);
|
||||||
|
if (lks == LK_SHARED)
|
||||||
|
vn_lock(vp, LK_DOWNGRADE | LK_RETRY, p);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* biosize = SSTOCN(smp->sm_share)->sc_txmax;*/
|
||||||
|
if (np->n_flag & NMODIFIED) {
|
||||||
|
smbfs_attr_cacheremove(vp);
|
||||||
|
error = VOP_GETATTR(vp, &vattr, cred, p);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
|
||||||
|
} else {
|
||||||
|
error = VOP_GETATTR(vp, &vattr, cred, p);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) {
|
||||||
|
error = smbfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
smb_makescred(&scred, p, cred);
|
||||||
|
return smb_read(smp->sm_share, np->n_fid, uiop, &scred);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smbfs_writevnode(struct vnode *vp, struct uio *uiop,
|
||||||
|
struct ucred *cred, int ioflag)
|
||||||
|
{
|
||||||
|
struct smbmount *smp = VTOSMBFS(vp);
|
||||||
|
struct smbnode *np = VTOSMB(vp);
|
||||||
|
struct smb_cred scred;
|
||||||
|
struct proc *p;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
if (vp->v_type != VREG) {
|
||||||
|
SMBERROR("vn types other than VREG unsupported !\n");
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
SMBVDEBUG("ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
|
||||||
|
if (uiop->uio_offset < 0)
|
||||||
|
return EINVAL;
|
||||||
|
/* if (uiop->uio_offset + uiop->uio_resid > smp->nm_maxfilesize)
|
||||||
|
return (EFBIG);*/
|
||||||
|
p = uiop->uio_procp;
|
||||||
|
if (ioflag & (IO_APPEND | IO_SYNC)) {
|
||||||
|
if (np->n_flag & NMODIFIED) {
|
||||||
|
smbfs_attr_cacheremove(vp);
|
||||||
|
error = smbfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if (ioflag & IO_APPEND) {
|
||||||
|
#if notyet
|
||||||
|
/*
|
||||||
|
* File size can be changed by another client
|
||||||
|
*/
|
||||||
|
smbfs_attr_cacheremove(vp);
|
||||||
|
error = VOP_GETATTR(vp, &vattr, cred, p);
|
||||||
|
if (error) return (error);
|
||||||
|
#endif
|
||||||
|
uiop->uio_offset = np->n_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uiop->uio_resid == 0)
|
||||||
|
return 0;
|
||||||
|
if (p && uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
|
||||||
|
psignal(p, SIGXFSZ);
|
||||||
|
return EFBIG;
|
||||||
|
}
|
||||||
|
smb_makescred(&scred, p, cred);
|
||||||
|
error = smb_write(smp->sm_share, np->n_fid, uiop, &scred);
|
||||||
|
SMBVDEBUG("after: ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
|
||||||
|
if (!error) {
|
||||||
|
if (uiop->uio_offset > np->n_size) {
|
||||||
|
np->n_size = uiop->uio_offset;
|
||||||
|
vnode_pager_setsize(vp, np->n_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do an I/O operation to/from a cache block.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smbfs_doio(struct buf *bp, struct ucred *cr, struct proc *p)
|
||||||
|
{
|
||||||
|
struct vnode *vp = bp->b_vp;
|
||||||
|
struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
|
||||||
|
struct smbnode *np = VTOSMB(vp);
|
||||||
|
struct uio uio, *uiop = &uio;
|
||||||
|
struct iovec io;
|
||||||
|
struct smb_cred scred;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
uiop->uio_iov = &io;
|
||||||
|
uiop->uio_iovcnt = 1;
|
||||||
|
uiop->uio_segflg = UIO_SYSSPACE;
|
||||||
|
uiop->uio_procp = p;
|
||||||
|
|
||||||
|
smb_makescred(&scred, p, cr);
|
||||||
|
|
||||||
|
if (bp->b_iocmd == BIO_READ) {
|
||||||
|
io.iov_len = uiop->uio_resid = bp->b_bcount;
|
||||||
|
io.iov_base = bp->b_data;
|
||||||
|
uiop->uio_rw = UIO_READ;
|
||||||
|
switch (vp->v_type) {
|
||||||
|
case VREG:
|
||||||
|
uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
|
||||||
|
error = smb_read(smp->sm_share, np->n_fid, uiop, &scred);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
if (uiop->uio_resid) {
|
||||||
|
int left = uiop->uio_resid;
|
||||||
|
int nread = bp->b_bcount - left;
|
||||||
|
if (left > 0)
|
||||||
|
bzero((char *)bp->b_data + nread, left);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("smbfs_doio: type %x unexpected\n",vp->v_type);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if (error) {
|
||||||
|
bp->b_error = error;
|
||||||
|
bp->b_ioflags |= BIO_ERROR;
|
||||||
|
}
|
||||||
|
} else { /* write */
|
||||||
|
if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
|
||||||
|
bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
|
||||||
|
|
||||||
|
if (bp->b_dirtyend > bp->b_dirtyoff) {
|
||||||
|
io.iov_len = uiop->uio_resid = bp->b_dirtyend - bp->b_dirtyoff;
|
||||||
|
uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
|
||||||
|
io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
|
||||||
|
uiop->uio_rw = UIO_WRITE;
|
||||||
|
bp->b_flags |= B_WRITEINPROG;
|
||||||
|
error = smb_write(smp->sm_share, np->n_fid, uiop, &scred);
|
||||||
|
bp->b_flags &= ~B_WRITEINPROG;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For an interrupted write, the buffer is still valid
|
||||||
|
* and the write hasn't been pushed to the server yet,
|
||||||
|
* so we can't set BIO_ERROR and report the interruption
|
||||||
|
* by setting B_EINTR. For the B_ASYNC case, B_EINTR
|
||||||
|
* is not relevant, so the rpc attempt is essentially
|
||||||
|
* a noop. For the case of a V3 write rpc not being
|
||||||
|
* committed to stable storage, the block is still
|
||||||
|
* dirty and requires either a commit rpc or another
|
||||||
|
* write rpc with iomode == NFSV3WRITE_FILESYNC before
|
||||||
|
* the block is reused. This is indicated by setting
|
||||||
|
* the B_DELWRI and B_NEEDCOMMIT flags.
|
||||||
|
*/
|
||||||
|
if (error == EINTR
|
||||||
|
|| (!error && (bp->b_flags & B_NEEDCOMMIT))) {
|
||||||
|
int s;
|
||||||
|
|
||||||
|
s = splbio();
|
||||||
|
bp->b_flags &= ~(B_INVAL|B_NOCACHE);
|
||||||
|
if ((bp->b_flags & B_ASYNC) == 0)
|
||||||
|
bp->b_flags |= B_EINTR;
|
||||||
|
if ((bp->b_flags & B_PAGING) == 0) {
|
||||||
|
bdirty(bp);
|
||||||
|
bp->b_flags &= ~B_DONE;
|
||||||
|
}
|
||||||
|
if ((bp->b_flags & B_ASYNC) == 0)
|
||||||
|
bp->b_flags |= B_EINTR;
|
||||||
|
splx(s);
|
||||||
|
} else {
|
||||||
|
if (error) {
|
||||||
|
bp->b_ioflags |= BIO_ERROR;
|
||||||
|
bp->b_error = error;
|
||||||
|
}
|
||||||
|
bp->b_dirtyoff = bp->b_dirtyend = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bp->b_resid = 0;
|
||||||
|
bufdone(bp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bp->b_resid = uiop->uio_resid;
|
||||||
|
bufdone(bp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vnode op for VM getpages.
|
||||||
|
* Wish wish .... get rid from multiple IO routines
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smbfs_getpages(ap)
|
||||||
|
struct vop_getpages_args /* {
|
||||||
|
struct vnode *a_vp;
|
||||||
|
vm_page_t *a_m;
|
||||||
|
int a_count;
|
||||||
|
int a_reqpage;
|
||||||
|
vm_ooffset_t a_offset;
|
||||||
|
} */ *ap;
|
||||||
|
{
|
||||||
|
#ifdef SMBFS_RWGENERIC
|
||||||
|
return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
|
||||||
|
ap->a_reqpage);
|
||||||
|
#else
|
||||||
|
int i, error, nextoff, size, toff, npages, count;
|
||||||
|
struct uio uio;
|
||||||
|
struct iovec iov;
|
||||||
|
vm_offset_t kva;
|
||||||
|
struct buf *bp;
|
||||||
|
struct vnode *vp;
|
||||||
|
struct proc *p;
|
||||||
|
struct ucred *cred;
|
||||||
|
struct smbmount *smp;
|
||||||
|
struct smbnode *np;
|
||||||
|
struct smb_cred scred;
|
||||||
|
vm_page_t *pages;
|
||||||
|
|
||||||
|
vp = ap->a_vp;
|
||||||
|
p = curproc; /* XXX */
|
||||||
|
cred = curproc->p_ucred; /* XXX */
|
||||||
|
np = VTOSMB(vp);
|
||||||
|
smp = VFSTOSMBFS(vp->v_mount);
|
||||||
|
pages = ap->a_m;
|
||||||
|
count = ap->a_count;
|
||||||
|
|
||||||
|
if (vp->v_object == NULL) {
|
||||||
|
printf("smbfs_getpages: called with non-merged cache vnode??\n");
|
||||||
|
return VM_PAGER_ERROR;
|
||||||
|
}
|
||||||
|
smb_makescred(&scred, p, cred);
|
||||||
|
|
||||||
|
#if __FreeBSD_version >= 400000
|
||||||
|
bp = getpbuf(&smbfs_pbuf_freecnt);
|
||||||
|
#else
|
||||||
|
bp = getpbuf();
|
||||||
|
#endif
|
||||||
|
npages = btoc(count);
|
||||||
|
kva = (vm_offset_t) bp->b_data;
|
||||||
|
pmap_qenter(kva, pages, npages);
|
||||||
|
|
||||||
|
iov.iov_base = (caddr_t) kva;
|
||||||
|
iov.iov_len = count;
|
||||||
|
uio.uio_iov = &iov;
|
||||||
|
uio.uio_iovcnt = 1;
|
||||||
|
uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
|
||||||
|
uio.uio_resid = count;
|
||||||
|
uio.uio_segflg = UIO_SYSSPACE;
|
||||||
|
uio.uio_rw = UIO_READ;
|
||||||
|
uio.uio_procp = p;
|
||||||
|
|
||||||
|
error = smb_read(smp->sm_share, np->n_fid, &uio, &scred);
|
||||||
|
pmap_qremove(kva, npages);
|
||||||
|
|
||||||
|
#if __FreeBSD_version >= 400000
|
||||||
|
relpbuf(bp, &smbfs_pbuf_freecnt);
|
||||||
|
#else
|
||||||
|
relpbuf(bp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (error && (uio.uio_resid == count)) {
|
||||||
|
printf("smbfs_getpages: error %d\n",error);
|
||||||
|
for (i = 0; i < npages; i++) {
|
||||||
|
if (ap->a_reqpage != i)
|
||||||
|
vnode_pager_freepage(pages[i]);
|
||||||
|
}
|
||||||
|
return VM_PAGER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = count - uio.uio_resid;
|
||||||
|
|
||||||
|
for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
|
||||||
|
vm_page_t m;
|
||||||
|
nextoff = toff + PAGE_SIZE;
|
||||||
|
m = pages[i];
|
||||||
|
|
||||||
|
m->flags &= ~PG_ZERO;
|
||||||
|
|
||||||
|
if (nextoff <= size) {
|
||||||
|
m->valid = VM_PAGE_BITS_ALL;
|
||||||
|
m->dirty = 0;
|
||||||
|
} else {
|
||||||
|
int nvalid = ((size + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1);
|
||||||
|
vm_page_set_validclean(m, 0, nvalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i != ap->a_reqpage) {
|
||||||
|
/*
|
||||||
|
* Whether or not to leave the page activated is up in
|
||||||
|
* the air, but we should put the page on a page queue
|
||||||
|
* somewhere (it already is in the object). Result:
|
||||||
|
* It appears that emperical results show that
|
||||||
|
* deactivating pages is best.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Just in case someone was asking for this page we
|
||||||
|
* now tell them that it is ok to use.
|
||||||
|
*/
|
||||||
|
if (!error) {
|
||||||
|
if (m->flags & PG_WANTED)
|
||||||
|
vm_page_activate(m);
|
||||||
|
else
|
||||||
|
vm_page_deactivate(m);
|
||||||
|
vm_page_wakeup(m);
|
||||||
|
} else {
|
||||||
|
vnode_pager_freepage(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#endif /* SMBFS_RWGENERIC */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vnode op for VM putpages.
|
||||||
|
* possible bug: all IO done in sync mode
|
||||||
|
* Note that vop_close always invalidate pages before close, so it's
|
||||||
|
* not necessary to open vnode.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smbfs_putpages(ap)
|
||||||
|
struct vop_putpages_args /* {
|
||||||
|
struct vnode *a_vp;
|
||||||
|
vm_page_t *a_m;
|
||||||
|
int a_count;
|
||||||
|
int a_sync;
|
||||||
|
int *a_rtvals;
|
||||||
|
vm_ooffset_t a_offset;
|
||||||
|
} */ *ap;
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
struct vnode *vp = ap->a_vp;
|
||||||
|
struct proc *p;
|
||||||
|
struct ucred *cred;
|
||||||
|
|
||||||
|
#ifdef SMBFS_RWGENERIC
|
||||||
|
p = curproc; /* XXX */
|
||||||
|
cred = p->p_ucred; /* XXX */
|
||||||
|
VOP_OPEN(vp, FWRITE, cred, p);
|
||||||
|
error = vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
|
||||||
|
ap->a_sync, ap->a_rtvals);
|
||||||
|
VOP_CLOSE(vp, FWRITE, cred, p);
|
||||||
|
return error;
|
||||||
|
#else
|
||||||
|
struct uio uio;
|
||||||
|
struct iovec iov;
|
||||||
|
vm_offset_t kva;
|
||||||
|
struct buf *bp;
|
||||||
|
int i, npages, count;
|
||||||
|
int *rtvals;
|
||||||
|
struct smbmount *smp;
|
||||||
|
struct smbnode *np;
|
||||||
|
struct smb_cred scred;
|
||||||
|
vm_page_t *pages;
|
||||||
|
|
||||||
|
p = curproc; /* XXX */
|
||||||
|
cred = p->p_ucred; /* XXX */
|
||||||
|
/* VOP_OPEN(vp, FWRITE, cred, p);*/
|
||||||
|
np = VTOSMB(vp);
|
||||||
|
smp = VFSTOSMBFS(vp->v_mount);
|
||||||
|
pages = ap->a_m;
|
||||||
|
count = ap->a_count;
|
||||||
|
rtvals = ap->a_rtvals;
|
||||||
|
npages = btoc(count);
|
||||||
|
|
||||||
|
for (i = 0; i < npages; i++) {
|
||||||
|
rtvals[i] = VM_PAGER_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __FreeBSD_version >= 400000
|
||||||
|
bp = getpbuf(&smbfs_pbuf_freecnt);
|
||||||
|
#else
|
||||||
|
bp = getpbuf();
|
||||||
|
#endif
|
||||||
|
kva = (vm_offset_t) bp->b_data;
|
||||||
|
pmap_qenter(kva, pages, npages);
|
||||||
|
|
||||||
|
iov.iov_base = (caddr_t) kva;
|
||||||
|
iov.iov_len = count;
|
||||||
|
uio.uio_iov = &iov;
|
||||||
|
uio.uio_iovcnt = 1;
|
||||||
|
uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
|
||||||
|
uio.uio_resid = count;
|
||||||
|
uio.uio_segflg = UIO_SYSSPACE;
|
||||||
|
uio.uio_rw = UIO_WRITE;
|
||||||
|
uio.uio_procp = p;
|
||||||
|
SMBVDEBUG("ofs=%d,resid=%d\n",(int)uio.uio_offset, uio.uio_resid);
|
||||||
|
|
||||||
|
smb_makescred(&scred, p, cred);
|
||||||
|
error = smb_write(smp->sm_share, np->n_fid, &uio, &scred);
|
||||||
|
/* VOP_CLOSE(vp, FWRITE, cred, p);*/
|
||||||
|
SMBVDEBUG("paged write done: %d\n", error);
|
||||||
|
|
||||||
|
pmap_qremove(kva, npages);
|
||||||
|
#if __FreeBSD_version >= 400000
|
||||||
|
relpbuf(bp, &smbfs_pbuf_freecnt);
|
||||||
|
#else
|
||||||
|
relpbuf(bp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
|
||||||
|
for (i = 0; i < nwritten; i++) {
|
||||||
|
rtvals[i] = VM_PAGER_OK;
|
||||||
|
pages[i]->dirty = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rtvals[0];
|
||||||
|
#endif /* SMBFS_RWGENERIC */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flush and invalidate all dirty buffers. If another process is already
|
||||||
|
* doing the flush, just wait for completion.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smbfs_vinvalbuf(vp, flags, cred, p, intrflg)
|
||||||
|
struct vnode *vp;
|
||||||
|
int flags;
|
||||||
|
struct ucred *cred;
|
||||||
|
struct proc *p;
|
||||||
|
int intrflg;
|
||||||
|
{
|
||||||
|
struct smbnode *np = VTOSMB(vp);
|
||||||
|
int error = 0, slpflag, slptimeo;
|
||||||
|
|
||||||
|
if (vp->v_flag & VXLOCK)
|
||||||
|
return 0;
|
||||||
|
if (intrflg) {
|
||||||
|
slpflag = PCATCH;
|
||||||
|
slptimeo = 2 * hz;
|
||||||
|
} else {
|
||||||
|
slpflag = 0;
|
||||||
|
slptimeo = 0;
|
||||||
|
}
|
||||||
|
while (np->n_flag & NFLUSHINPROG) {
|
||||||
|
np->n_flag |= NFLUSHWANT;
|
||||||
|
error = tsleep((caddr_t)&np->n_flag, PRIBIO + 2, "smfsvinv", slptimeo);
|
||||||
|
error = smb_proc_intr(p);
|
||||||
|
if (error == EINTR && intrflg)
|
||||||
|
return EINTR;
|
||||||
|
}
|
||||||
|
np->n_flag |= NFLUSHINPROG;
|
||||||
|
error = vinvalbuf(vp, flags, cred, p, slpflag, 0);
|
||||||
|
while (error) {
|
||||||
|
if (intrflg && (error == ERESTART || error == EINTR)) {
|
||||||
|
np->n_flag &= ~NFLUSHINPROG;
|
||||||
|
if (np->n_flag & NFLUSHWANT) {
|
||||||
|
np->n_flag &= ~NFLUSHWANT;
|
||||||
|
wakeup((caddr_t)&np->n_flag);
|
||||||
|
}
|
||||||
|
return EINTR;
|
||||||
|
}
|
||||||
|
error = vinvalbuf(vp, flags, cred, p, slpflag, 0);
|
||||||
|
}
|
||||||
|
np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
|
||||||
|
if (np->n_flag & NFLUSHWANT) {
|
||||||
|
np->n_flag &= ~NFLUSHWANT;
|
||||||
|
wakeup((caddr_t)&np->n_flag);
|
||||||
|
}
|
||||||
|
return (error);
|
||||||
|
}
|
415
sys/fs/smbfs/smbfs_node.c
Normal file
415
sys/fs/smbfs/smbfs_node.c
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001 Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/vnode.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <vm/vm.h>
|
||||||
|
#include <vm/vm_extern.h>
|
||||||
|
/*#include <vm/vm_page.h>
|
||||||
|
#include <vm/vm_object.h>*/
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
|
||||||
|
#include <fs/smbfs/smbfs.h>
|
||||||
|
#include <fs/smbfs/smbfs_node.h>
|
||||||
|
#include <fs/smbfs/smbfs_subr.h>
|
||||||
|
|
||||||
|
#define SMBFS_NOHASH(smp, hval) (&(smp)->sm_hash[(hval) & (smp)->sm_hashlen])
|
||||||
|
#define smbfs_hash_lock(smp, p) lockmgr(&smp->sm_hashlock, LK_EXCLUSIVE, NULL, p)
|
||||||
|
#define smbfs_hash_unlock(smp, p) lockmgr(&smp->sm_hashlock, LK_RELEASE, NULL, p)
|
||||||
|
|
||||||
|
|
||||||
|
extern vop_t **smbfs_vnodeop_p;
|
||||||
|
|
||||||
|
MALLOC_DEFINE(M_SMBNODE, "SMBFS node", "SMBFS vnode private part");
|
||||||
|
static MALLOC_DEFINE(M_SMBNODENAME, "SMBFS nname", "SMBFS node name");
|
||||||
|
|
||||||
|
int smbfs_hashprint(struct mount *mp);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
extern struct linker_set sysctl_vfs_smbfs;
|
||||||
|
#ifdef SYSCTL_DECL
|
||||||
|
SYSCTL_DECL(_vfs_smbfs);
|
||||||
|
#endif
|
||||||
|
SYSCTL_PROC(_vfs_smbfs, OID_AUTO, vnprint, CTLFLAG_WR|CTLTYPE_OPAQUE,
|
||||||
|
NULL, 0, smbfs_hashprint, "S,vnlist", "vnode hash");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FNV_32_PRIME ((u_int32_t) 0x01000193UL)
|
||||||
|
#define FNV1_32_INIT ((u_int32_t) 33554467UL)
|
||||||
|
|
||||||
|
u_int32_t
|
||||||
|
smbfs_hash(const u_char *name, int nmlen)
|
||||||
|
{
|
||||||
|
u_int32_t v;
|
||||||
|
|
||||||
|
for (v = FNV1_32_INIT; nmlen; name++, nmlen--) {
|
||||||
|
v *= FNV_32_PRIME;
|
||||||
|
v ^= (u_int32_t)*name;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smbfs_hashprint(struct mount *mp)
|
||||||
|
{
|
||||||
|
struct smbmount *smp = VFSTOSMBFS(mp);
|
||||||
|
struct smbnode_hashhead *nhpp;
|
||||||
|
struct smbnode *np;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i <= smp->sm_hashlen; i++) {
|
||||||
|
nhpp = &smp->sm_hash[i];
|
||||||
|
LIST_FOREACH(np, nhpp, n_hash)
|
||||||
|
vprint(NULL, SMBTOV(np));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
smbfs_name_alloc(const u_char *name, int nmlen)
|
||||||
|
{
|
||||||
|
u_char *cp;
|
||||||
|
|
||||||
|
nmlen++;
|
||||||
|
#ifdef SMBFS_NAME_DEBUG
|
||||||
|
cp = malloc(nmlen + 2 + sizeof(int), M_SMBNODENAME, M_WAITOK);
|
||||||
|
*(int*)cp = nmlen;
|
||||||
|
cp += sizeof(int);
|
||||||
|
cp[0] = 0xfc;
|
||||||
|
cp++;
|
||||||
|
bcopy(name, cp, nmlen - 1);
|
||||||
|
cp[nmlen] = 0xfe;
|
||||||
|
#else
|
||||||
|
cp = malloc(nmlen, M_SMBNODENAME, M_WAITOK);
|
||||||
|
bcopy(name, cp, nmlen - 1);
|
||||||
|
#endif
|
||||||
|
cp[nmlen - 1] = 0;
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smbfs_name_free(u_char *name)
|
||||||
|
{
|
||||||
|
#ifdef SMBFS_NAME_DEBUG
|
||||||
|
int nmlen, slen;
|
||||||
|
u_char *cp;
|
||||||
|
|
||||||
|
cp = name;
|
||||||
|
cp--;
|
||||||
|
if (*cp != 0xfc) {
|
||||||
|
printf("First byte of name entry '%s' corrupted\n", name);
|
||||||
|
Debugger("ditto");
|
||||||
|
}
|
||||||
|
cp -= sizeof(int);
|
||||||
|
nmlen = *(int*)cp;
|
||||||
|
slen = strlen(name) + 1;
|
||||||
|
if (nmlen != slen) {
|
||||||
|
printf("Name length mismatch: was %d, now %d name '%s'\n",
|
||||||
|
nmlen, slen, name);
|
||||||
|
Debugger("ditto");
|
||||||
|
}
|
||||||
|
if (name[nmlen] != 0xfe) {
|
||||||
|
printf("Last byte of name entry '%s' corrupted\n", name);
|
||||||
|
Debugger("ditto");
|
||||||
|
}
|
||||||
|
free(cp, M_SMBNODENAME);
|
||||||
|
#else
|
||||||
|
free(name, M_SMBNODENAME);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smbfs_node_alloc(struct mount *mp, struct vnode *dvp,
|
||||||
|
const char *name, int nmlen, struct smbfattr *fap, struct vnode **vpp)
|
||||||
|
{
|
||||||
|
struct proc *p = curproc; /* XXX */
|
||||||
|
struct smbmount *smp = VFSTOSMBFS(mp);
|
||||||
|
struct smbnode_hashhead *nhpp;
|
||||||
|
struct smbnode *np, *np2, *dnp;
|
||||||
|
struct vnode *vp;
|
||||||
|
u_long hashval;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
*vpp = NULL;
|
||||||
|
if (smp->sm_root != NULL && dvp == NULL) {
|
||||||
|
SMBERROR("do not allocate root vnode twice!\n");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
if (nmlen == 2 && bcmp(name, "..", 2) == 0) {
|
||||||
|
if (dvp == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
vp = VTOSMB(dvp)->n_parent->n_vnode;
|
||||||
|
error = vget(vp, LK_EXCLUSIVE, p);
|
||||||
|
if (error == 0)
|
||||||
|
*vpp = vp;
|
||||||
|
return error;
|
||||||
|
} else if (nmlen == 1 && name[0] == '.') {
|
||||||
|
SMBERROR("do not call me with dot!\n");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
dnp = dvp ? VTOSMB(dvp) : NULL;
|
||||||
|
if (dnp == NULL && dvp != NULL) {
|
||||||
|
vprint("smbfs_node_alloc: dead parent vnode", dvp);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
hashval = smbfs_hash(name, nmlen);
|
||||||
|
retry:
|
||||||
|
smbfs_hash_lock(smp, p);
|
||||||
|
loop:
|
||||||
|
nhpp = SMBFS_NOHASH(smp, hashval);
|
||||||
|
LIST_FOREACH(np, nhpp, n_hash) {
|
||||||
|
vp = SMBTOV(np);
|
||||||
|
if (np->n_parent != dnp ||
|
||||||
|
np->n_nmlen != nmlen || bcmp(name, np->n_name, nmlen) != 0)
|
||||||
|
continue;
|
||||||
|
VI_LOCK(vp);
|
||||||
|
smbfs_hash_unlock(smp, p);
|
||||||
|
if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p) != 0)
|
||||||
|
goto retry;
|
||||||
|
*vpp = vp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
smbfs_hash_unlock(smp, p);
|
||||||
|
/*
|
||||||
|
* If we don't have node attributes, then it is an explicit lookup
|
||||||
|
* for an existing vnode.
|
||||||
|
*/
|
||||||
|
if (fap == NULL)
|
||||||
|
return ENOENT;
|
||||||
|
|
||||||
|
MALLOC(np, struct smbnode *, sizeof *np, M_SMBNODE, M_WAITOK);
|
||||||
|
error = getnewvnode(VT_SMBFS, mp, smbfs_vnodeop_p, &vp);
|
||||||
|
if (error) {
|
||||||
|
FREE(np, M_SMBNODE);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
vp->v_type = fap->fa_attr & SMB_FA_DIR ? VDIR : VREG;
|
||||||
|
bzero(np, sizeof(*np));
|
||||||
|
vp->v_data = np;
|
||||||
|
np->n_vnode = vp;
|
||||||
|
np->n_mount = VFSTOSMBFS(mp);
|
||||||
|
np->n_nmlen = nmlen;
|
||||||
|
np->n_name = smbfs_name_alloc(name, nmlen);
|
||||||
|
np->n_ino = fap->fa_ino;
|
||||||
|
|
||||||
|
if (dvp) {
|
||||||
|
np->n_parent = dnp;
|
||||||
|
if (/*vp->v_type == VDIR &&*/ (dvp->v_flag & VROOT) == 0) {
|
||||||
|
vref(dvp);
|
||||||
|
np->n_flag |= NREFPARENT;
|
||||||
|
}
|
||||||
|
} else if (vp->v_type == VREG)
|
||||||
|
SMBERROR("new vnode '%s' born without parent ?\n", np->n_name);
|
||||||
|
|
||||||
|
lockinit(&vp->v_lock, PINOD, "smbnode", 0, LK_CANRECURSE);
|
||||||
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||||
|
|
||||||
|
smbfs_hash_lock(smp, p);
|
||||||
|
LIST_FOREACH(np2, nhpp, n_hash) {
|
||||||
|
if (np2->n_parent != dnp ||
|
||||||
|
np2->n_nmlen != nmlen || bcmp(name, np2->n_name, nmlen) != 0)
|
||||||
|
continue;
|
||||||
|
vput(vp);
|
||||||
|
/* smb_name_free(np->n_name);
|
||||||
|
FREE(np, M_SMBNODE);*/
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
LIST_INSERT_HEAD(nhpp, np, n_hash);
|
||||||
|
smbfs_hash_unlock(smp, p);
|
||||||
|
*vpp = vp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen,
|
||||||
|
struct smbfattr *fap, struct vnode **vpp)
|
||||||
|
{
|
||||||
|
struct smbnode *np;
|
||||||
|
struct vnode *vp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
*vpp = NULL;
|
||||||
|
error = smbfs_node_alloc(mp, dvp, name, nmlen, fap, &vp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
np = VTOSMB(vp);
|
||||||
|
if (fap)
|
||||||
|
smbfs_attr_cacheenter(vp, fap);
|
||||||
|
*vpp = vp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free smbnode, and give vnode back to system
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smbfs_reclaim(ap)
|
||||||
|
struct vop_reclaim_args /* {
|
||||||
|
struct vnode *a_vp;
|
||||||
|
struct proc *a_p;
|
||||||
|
} */ *ap;
|
||||||
|
{
|
||||||
|
struct vnode *vp = ap->a_vp;
|
||||||
|
struct proc *p = ap->a_p;
|
||||||
|
struct vnode *dvp;
|
||||||
|
struct smbnode *np = VTOSMB(vp);
|
||||||
|
struct smbmount *smp = VTOSMBFS(vp);
|
||||||
|
|
||||||
|
SMBVDEBUG("%s,%d\n", np->n_name, vp->v_usecount);
|
||||||
|
|
||||||
|
smbfs_hash_lock(smp, p);
|
||||||
|
|
||||||
|
dvp = (np->n_parent && (np->n_flag & NREFPARENT)) ?
|
||||||
|
np->n_parent->n_vnode : NULL;
|
||||||
|
|
||||||
|
if (np->n_hash.le_prev)
|
||||||
|
LIST_REMOVE(np, n_hash);
|
||||||
|
cache_purge(vp);
|
||||||
|
if (smp->sm_root == np) {
|
||||||
|
SMBVDEBUG("root vnode\n");
|
||||||
|
smp->sm_root = NULL;
|
||||||
|
}
|
||||||
|
vp->v_data = NULL;
|
||||||
|
smbfs_hash_unlock(smp, p);
|
||||||
|
if (np->n_name)
|
||||||
|
smbfs_name_free(np->n_name);
|
||||||
|
FREE(np, M_SMBNODE);
|
||||||
|
if (dvp) {
|
||||||
|
VI_LOCK(dvp);
|
||||||
|
if (dvp->v_usecount >= 1) {
|
||||||
|
VI_UNLOCK(dvp);
|
||||||
|
vrele(dvp);
|
||||||
|
} else {
|
||||||
|
VI_UNLOCK(dvp);
|
||||||
|
SMBERROR("BUG: negative use count for parent!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smbfs_inactive(ap)
|
||||||
|
struct vop_inactive_args /* {
|
||||||
|
struct vnode *a_vp;
|
||||||
|
struct proc *a_p;
|
||||||
|
} */ *ap;
|
||||||
|
{
|
||||||
|
struct proc *p = ap->a_p;
|
||||||
|
struct ucred *cred = p->p_ucred;
|
||||||
|
struct vnode *vp = ap->a_vp;
|
||||||
|
struct smbnode *np = VTOSMB(vp);
|
||||||
|
struct smb_cred scred;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
SMBVDEBUG("%s: %d\n", VTOSMB(vp)->n_name, vp->v_usecount);
|
||||||
|
if (np->n_opencount) {
|
||||||
|
error = smbfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
|
||||||
|
smb_makescred(&scred, p, cred);
|
||||||
|
error = smbfs_smb_close(np->n_mount->sm_share, np->n_fid,
|
||||||
|
&np->n_mtime, &scred);
|
||||||
|
np->n_opencount = 0;
|
||||||
|
}
|
||||||
|
VOP_UNLOCK(vp, 0, p);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* routines to maintain vnode attributes cache
|
||||||
|
* smbfs_attr_cacheenter: unpack np.i to vattr structure
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
smbfs_attr_cacheenter(struct vnode *vp, struct smbfattr *fap)
|
||||||
|
{
|
||||||
|
struct smbnode *np = VTOSMB(vp);
|
||||||
|
|
||||||
|
if (vp->v_type == VREG) {
|
||||||
|
if (np->n_size != fap->fa_size) {
|
||||||
|
np->n_size = fap->fa_size;
|
||||||
|
vnode_pager_setsize(vp, np->n_size);
|
||||||
|
}
|
||||||
|
} else if (vp->v_type == VDIR) {
|
||||||
|
np->n_size = 16384; /* should be a better way ... */
|
||||||
|
} else
|
||||||
|
return;
|
||||||
|
np->n_mtime = fap->fa_mtime;
|
||||||
|
np->n_dosattr = fap->fa_attr;
|
||||||
|
np->n_attrage = time_second;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smbfs_attr_cachelookup(struct vnode *vp, struct vattr *va)
|
||||||
|
{
|
||||||
|
struct smbnode *np = VTOSMB(vp);
|
||||||
|
struct smbmount *smp = VTOSMBFS(vp);
|
||||||
|
int diff;
|
||||||
|
|
||||||
|
diff = time_second - np->n_attrage;
|
||||||
|
if (diff > 2) /* XXX should be configurable */
|
||||||
|
return ENOENT;
|
||||||
|
va->va_type = vp->v_type; /* vnode type (for create) */
|
||||||
|
if (vp->v_type == VREG) {
|
||||||
|
va->va_mode = smp->sm_args.file_mode; /* files access mode and type */
|
||||||
|
} else if (vp->v_type == VDIR) {
|
||||||
|
va->va_mode = smp->sm_args.dir_mode; /* files access mode and type */
|
||||||
|
} else
|
||||||
|
return EINVAL;
|
||||||
|
va->va_size = np->n_size;
|
||||||
|
va->va_nlink = 1; /* number of references to file */
|
||||||
|
va->va_uid = smp->sm_args.uid; /* owner user id */
|
||||||
|
va->va_gid = smp->sm_args.gid; /* owner group id */
|
||||||
|
va->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
|
||||||
|
va->va_fileid = np->n_ino; /* file id */
|
||||||
|
if (va->va_fileid == 0)
|
||||||
|
va->va_fileid = 2;
|
||||||
|
va->va_blocksize = SSTOVC(smp->sm_share)->vc_txmax;
|
||||||
|
va->va_mtime = np->n_mtime;
|
||||||
|
va->va_atime = va->va_ctime = va->va_mtime; /* time file changed */
|
||||||
|
va->va_gen = VNOVAL; /* generation number of file */
|
||||||
|
va->va_flags = 0; /* flags defined for file */
|
||||||
|
va->va_rdev = VNOVAL; /* device the special file represents */
|
||||||
|
va->va_bytes = va->va_size; /* bytes of disk space held by file */
|
||||||
|
va->va_filerev = 0; /* file modification number */
|
||||||
|
va->va_vaflags = 0; /* operations flags */
|
||||||
|
return 0;
|
||||||
|
}
|
100
sys/fs/smbfs/smbfs_node.h
Normal file
100
sys/fs/smbfs/smbfs_node.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001, Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#ifndef _FS_SMBFS_NODE_H_
|
||||||
|
#define _FS_SMBFS_NODE_H_
|
||||||
|
|
||||||
|
#define SMBFS_ROOT_INO 2 /* just like in UFS */
|
||||||
|
|
||||||
|
/* Bits for smbnode.n_flag */
|
||||||
|
#define NFLUSHINPROG 0x0001
|
||||||
|
#define NFLUSHWANT 0x0002 /* they should gone ... */
|
||||||
|
#define NMODIFIED 0x0004 /* bogus, until async IO implemented */
|
||||||
|
/*efine NNEW 0x0008*//* smb/vnode has been allocated */
|
||||||
|
#define NREFPARENT 0x0010 /* node holds parent from recycling */
|
||||||
|
|
||||||
|
struct smbfs_fctx;
|
||||||
|
|
||||||
|
struct smbnode {
|
||||||
|
#ifndef FB_CURRENT
|
||||||
|
struct lock n_lock; /* smbnode lock. (mbf) */
|
||||||
|
#endif
|
||||||
|
int n_flag;
|
||||||
|
struct smbnode * n_parent;
|
||||||
|
struct vnode * n_vnode;
|
||||||
|
struct smbmount * n_mount;
|
||||||
|
time_t n_attrage; /* attributes cache time */
|
||||||
|
/* time_t n_ctime;*/
|
||||||
|
struct timespec n_mtime; /* modify time */
|
||||||
|
struct timespec n_atime; /* last access time */
|
||||||
|
u_quad_t n_size;
|
||||||
|
long n_ino;
|
||||||
|
int n_dosattr;
|
||||||
|
int n_opencount;
|
||||||
|
u_int16_t n_fid; /* file handle */
|
||||||
|
int n_rwstate; /* granted access mode */
|
||||||
|
u_char n_nmlen;
|
||||||
|
u_char * n_name;
|
||||||
|
struct smbfs_fctx * n_dirseq; /* ff context */
|
||||||
|
long n_dirofs; /* last ff offset */
|
||||||
|
struct lockf * n_lockf; /* Locking records of file */
|
||||||
|
LIST_ENTRY(smbnode) n_hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define VTOSMB(vp) ((struct smbnode *)(vp)->v_data)
|
||||||
|
#define SMBTOV(np) ((struct vnode *)(np)->n_vnode)
|
||||||
|
|
||||||
|
struct vop_getpages_args;
|
||||||
|
struct vop_inactive_args;
|
||||||
|
struct vop_putpages_args;
|
||||||
|
struct vop_reclaim_args;
|
||||||
|
struct ucred;
|
||||||
|
struct uio;
|
||||||
|
struct smbfattr;
|
||||||
|
|
||||||
|
int smbfs_inactive(struct vop_inactive_args *);
|
||||||
|
int smbfs_reclaim(struct vop_reclaim_args *);
|
||||||
|
int smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen,
|
||||||
|
struct smbfattr *fap, struct vnode **vpp);
|
||||||
|
u_int32_t smbfs_hash(const u_char *name, int nmlen);
|
||||||
|
|
||||||
|
int smbfs_getpages(struct vop_getpages_args *);
|
||||||
|
int smbfs_putpages(struct vop_putpages_args *);
|
||||||
|
int smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred);
|
||||||
|
int smbfs_writevnode(struct vnode *vp, struct uio *uiop, struct ucred *cred, int ioflag);
|
||||||
|
void smbfs_attr_cacheenter(struct vnode *vp, struct smbfattr *fap);
|
||||||
|
int smbfs_attr_cachelookup(struct vnode *vp ,struct vattr *va);
|
||||||
|
|
||||||
|
#define smbfs_attr_cacheremove(vp) VTOSMB(vp)->n_attrage = 0
|
||||||
|
|
||||||
|
#endif /* _FS_SMBFS_NODE_H_ */
|
1273
sys/fs/smbfs/smbfs_smb.c
Normal file
1273
sys/fs/smbfs/smbfs_smb.c
Normal file
File diff suppressed because it is too large
Load Diff
326
sys/fs/smbfs/smbfs_subr.c
Normal file
326
sys/fs/smbfs/smbfs_subr.c
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001, Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <machine/clock.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/vnode.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/iconv.h>
|
||||||
|
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
#include <netsmb/smb_rq.h>
|
||||||
|
#include <netsmb/smb_dev.h>
|
||||||
|
|
||||||
|
#include <fs/smbfs/smbfs.h>
|
||||||
|
#include <fs/smbfs/smbfs_node.h>
|
||||||
|
#include <fs/smbfs/smbfs_subr.h>
|
||||||
|
|
||||||
|
MALLOC_DEFINE(M_SMBFSDATA, "SMBFS data", "SMBFS private data");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time & date conversion routines taken from msdosfs. Although leap
|
||||||
|
* year calculation is bogus, it's sufficient before 2100 :)
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* This is the format of the contents of the deTime field in the direntry
|
||||||
|
* structure.
|
||||||
|
* We don't use bitfields because we don't know how compilers for
|
||||||
|
* arbitrary machines will lay them out.
|
||||||
|
*/
|
||||||
|
#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */
|
||||||
|
#define DT_2SECONDS_SHIFT 0
|
||||||
|
#define DT_MINUTES_MASK 0x7E0 /* minutes */
|
||||||
|
#define DT_MINUTES_SHIFT 5
|
||||||
|
#define DT_HOURS_MASK 0xF800 /* hours */
|
||||||
|
#define DT_HOURS_SHIFT 11
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the format of the contents of the deDate field in the direntry
|
||||||
|
* structure.
|
||||||
|
*/
|
||||||
|
#define DD_DAY_MASK 0x1F /* day of month */
|
||||||
|
#define DD_DAY_SHIFT 0
|
||||||
|
#define DD_MONTH_MASK 0x1E0 /* month */
|
||||||
|
#define DD_MONTH_SHIFT 5
|
||||||
|
#define DD_YEAR_MASK 0xFE00 /* year - 1980 */
|
||||||
|
#define DD_YEAR_SHIFT 9
|
||||||
|
/*
|
||||||
|
* Total number of days that have passed for each month in a regular year.
|
||||||
|
*/
|
||||||
|
static u_short regyear[] = {
|
||||||
|
31, 59, 90, 120, 151, 181,
|
||||||
|
212, 243, 273, 304, 334, 365
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Total number of days that have passed for each month in a leap year.
|
||||||
|
*/
|
||||||
|
static u_short leapyear[] = {
|
||||||
|
31, 60, 91, 121, 152, 182,
|
||||||
|
213, 244, 274, 305, 335, 366
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables used to remember parts of the last time conversion. Maybe we
|
||||||
|
* can avoid a full conversion.
|
||||||
|
*/
|
||||||
|
static u_long lasttime;
|
||||||
|
static u_long lastday;
|
||||||
|
static u_short lastddate;
|
||||||
|
static u_short lastdtime;
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_time_local2server(struct timespec *tsp, int tzoff, u_long *seconds)
|
||||||
|
{
|
||||||
|
*seconds = tsp->tv_sec - tzoff * 60 /*- tz.tz_minuteswest * 60 -
|
||||||
|
(wall_cmos_clock ? adjkerntz : 0)*/;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_time_server2local(u_long seconds, int tzoff, struct timespec *tsp)
|
||||||
|
{
|
||||||
|
tsp->tv_sec = seconds + tzoff * 60;
|
||||||
|
/*+ tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0)*/;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of seconds between 1970 and 1601 year
|
||||||
|
*/
|
||||||
|
int64_t DIFF1970TO1601 = 11644473600ULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time from server comes as UTC, so no need to use tz
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
smb_time_NT2local(int64_t nsec, int tzoff, struct timespec *tsp)
|
||||||
|
{
|
||||||
|
smb_time_server2local(nsec / 10000000 - DIFF1970TO1601, 0, tsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_time_local2NT(struct timespec *tsp, int tzoff, int64_t *nsec)
|
||||||
|
{
|
||||||
|
u_long seconds;
|
||||||
|
|
||||||
|
smb_time_local2server(tsp, 0, &seconds);
|
||||||
|
*nsec = (((int64_t)(seconds) & ~1) + DIFF1970TO1601) * (int64_t)10000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp,
|
||||||
|
u_int16_t *dtp, u_int8_t *dhp)
|
||||||
|
{
|
||||||
|
u_long t, days, year, month, inc;
|
||||||
|
u_short *months;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the time from the last conversion is the same as now, then
|
||||||
|
* skip the computations and use the saved result.
|
||||||
|
*/
|
||||||
|
smb_time_local2server(tsp, tzoff, &t);
|
||||||
|
t &= ~1;
|
||||||
|
if (lasttime != t) {
|
||||||
|
lasttime = t;
|
||||||
|
lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
|
||||||
|
+ (((t / 60) % 60) << DT_MINUTES_SHIFT)
|
||||||
|
+ (((t / 3600) % 24) << DT_HOURS_SHIFT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the number of days since 1970 is the same as the last
|
||||||
|
* time we did the computation then skip all this leap year
|
||||||
|
* and month stuff.
|
||||||
|
*/
|
||||||
|
days = t / (24 * 60 * 60);
|
||||||
|
if (days != lastday) {
|
||||||
|
lastday = days;
|
||||||
|
for (year = 1970;; year++) {
|
||||||
|
inc = year & 0x03 ? 365 : 366;
|
||||||
|
if (days < inc)
|
||||||
|
break;
|
||||||
|
days -= inc;
|
||||||
|
}
|
||||||
|
months = year & 0x03 ? regyear : leapyear;
|
||||||
|
for (month = 0; days >= months[month]; month++)
|
||||||
|
;
|
||||||
|
if (month > 0)
|
||||||
|
days -= months[month - 1];
|
||||||
|
lastddate = ((days + 1) << DD_DAY_SHIFT)
|
||||||
|
+ ((month + 1) << DD_MONTH_SHIFT);
|
||||||
|
/*
|
||||||
|
* Remember dos's idea of time is relative to 1980.
|
||||||
|
* unix's is relative to 1970. If somehow we get a
|
||||||
|
* time before 1980 then don't give totally crazy
|
||||||
|
* results.
|
||||||
|
*/
|
||||||
|
if (year > 1980)
|
||||||
|
lastddate += (year - 1980) << DD_YEAR_SHIFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dtp)
|
||||||
|
*dtp = lastdtime;
|
||||||
|
if (dhp)
|
||||||
|
*dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
|
||||||
|
|
||||||
|
*ddp = lastddate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
|
||||||
|
* interval there were 8 regular years and 2 leap years.
|
||||||
|
*/
|
||||||
|
#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
|
||||||
|
|
||||||
|
static u_short lastdosdate;
|
||||||
|
static u_long lastseconds;
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_dos2unixtime(u_int dd, u_int dt, u_int dh, int tzoff,
|
||||||
|
struct timespec *tsp)
|
||||||
|
{
|
||||||
|
u_long seconds;
|
||||||
|
u_long month;
|
||||||
|
u_long year;
|
||||||
|
u_long days;
|
||||||
|
u_short *months;
|
||||||
|
|
||||||
|
if (dd == 0) {
|
||||||
|
tsp->tv_sec = 0;
|
||||||
|
tsp->tv_nsec = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
|
||||||
|
+ ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
|
||||||
|
+ ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
|
||||||
|
+ dh / 100;
|
||||||
|
/*
|
||||||
|
* If the year, month, and day from the last conversion are the
|
||||||
|
* same then use the saved value.
|
||||||
|
*/
|
||||||
|
if (lastdosdate != dd) {
|
||||||
|
lastdosdate = dd;
|
||||||
|
days = 0;
|
||||||
|
year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
|
||||||
|
days = year * 365;
|
||||||
|
days += year / 4 + 1; /* add in leap days */
|
||||||
|
if ((year & 0x03) == 0)
|
||||||
|
days--; /* if year is a leap year */
|
||||||
|
months = year & 0x03 ? regyear : leapyear;
|
||||||
|
month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
|
||||||
|
if (month < 1 || month > 12) {
|
||||||
|
month = 1;
|
||||||
|
}
|
||||||
|
if (month > 1)
|
||||||
|
days += months[month - 2];
|
||||||
|
days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
|
||||||
|
lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
|
||||||
|
}
|
||||||
|
smb_time_server2local(seconds + lastseconds, tzoff, tsp);
|
||||||
|
tsp->tv_nsec = (dh % 100) * 10000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_fphelp(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *np,
|
||||||
|
int caseopt)
|
||||||
|
{
|
||||||
|
struct smbmount *smp= np->n_mount;
|
||||||
|
struct smbnode **npp = smp->sm_npstack;
|
||||||
|
int i, error = 0;
|
||||||
|
|
||||||
|
/* simple_lock(&smp->sm_npslock);*/
|
||||||
|
i = 0;
|
||||||
|
while (np->n_parent) {
|
||||||
|
if (i++ == SMBFS_MAXPATHCOMP) {
|
||||||
|
/* simple_unlock(&smp->sm_npslock);*/
|
||||||
|
return ENAMETOOLONG;
|
||||||
|
}
|
||||||
|
*npp++ = np;
|
||||||
|
np = np->n_parent;
|
||||||
|
}
|
||||||
|
/* if (i == 0)
|
||||||
|
return smb_put_dmem(mbp, vcp, "\\", 2, caseopt);*/
|
||||||
|
while (i--) {
|
||||||
|
np = *--npp;
|
||||||
|
error = mb_put_uint8(mbp, '\\');
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
error = smb_put_dmem(mbp, vcp, np->n_name, np->n_nmlen, caseopt);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* simple_unlock(&smp->sm_npslock);*/
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
|
||||||
|
const char *name, int nmlen)
|
||||||
|
{
|
||||||
|
int caseopt = SMB_CS_NONE;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
|
||||||
|
caseopt |= SMB_CS_UPPER;
|
||||||
|
if (dnp != NULL) {
|
||||||
|
error = smb_fphelp(mbp, vcp, dnp, caseopt);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if (name) {
|
||||||
|
error = mb_put_uint8(mbp, '\\');
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
error = mb_put_uint8(mbp, 0);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smbfs_fname_tolocal(struct smb_vc *vcp, char *name, int nmlen, int caseopt)
|
||||||
|
{
|
||||||
|
/* if (caseopt & SMB_CS_UPPER)
|
||||||
|
iconv_convmem(vcp->vc_toupper, name, name, nmlen);
|
||||||
|
else if (caseopt & SMB_CS_LOWER)
|
||||||
|
iconv_convmem(vcp->vc_tolower, name, name, nmlen);*/
|
||||||
|
if (vcp->vc_tolocal)
|
||||||
|
iconv_convmem(vcp->vc_tolocal, name, name, nmlen);
|
||||||
|
return 0;
|
||||||
|
}
|
187
sys/fs/smbfs/smbfs_subr.h
Normal file
187
sys/fs/smbfs/smbfs_subr.h
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001, Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#ifndef _FS_SMBFS_SMBFS_SUBR_H_
|
||||||
|
#define _FS_SMBFS_SMBFS_SUBR_H_
|
||||||
|
|
||||||
|
#ifdef MALLOC_DECLARE
|
||||||
|
MALLOC_DECLARE(M_SMBFSDATA);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SMBFSERR(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
|
||||||
|
|
||||||
|
#ifdef SMB_VNODE_DEBUG
|
||||||
|
#define SMBVDEBUG(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
|
||||||
|
#else
|
||||||
|
#define SMBVDEBUG(format, args...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Possible lock commands
|
||||||
|
*/
|
||||||
|
#define SMB_LOCK_EXCL 0
|
||||||
|
#define SMB_LOCK_SHARED 1
|
||||||
|
#define SMB_LOCK_RELEASE 2
|
||||||
|
|
||||||
|
struct smbmount;
|
||||||
|
struct proc;
|
||||||
|
struct timespec;
|
||||||
|
struct ucred;
|
||||||
|
struct vattr;
|
||||||
|
struct vnode;
|
||||||
|
struct statfs;
|
||||||
|
|
||||||
|
struct smbfattr {
|
||||||
|
int fa_attr;
|
||||||
|
int64_t fa_size;
|
||||||
|
struct timespec fa_atime;
|
||||||
|
struct timespec fa_ctime;
|
||||||
|
struct timespec fa_mtime;
|
||||||
|
long fa_ino;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Context to perform findfirst/findnext/findclose operations
|
||||||
|
*/
|
||||||
|
#define SMBFS_RDD_FINDFIRST 0x01
|
||||||
|
#define SMBFS_RDD_EOF 0x02
|
||||||
|
#define SMBFS_RDD_FINDSINGLE 0x04
|
||||||
|
#define SMBFS_RDD_USESEARCH 0x08
|
||||||
|
#define SMBFS_RDD_NOCLOSE 0x10
|
||||||
|
#define SMBFS_RDD_GOTRNAME 0x1000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search context supplied by server
|
||||||
|
*/
|
||||||
|
#define SMB_SKEYLEN 21 /* search context */
|
||||||
|
#define SMB_DENTRYLEN (SMB_SKEYLEN + 22) /* entire entry */
|
||||||
|
|
||||||
|
struct smbfs_fctx {
|
||||||
|
/*
|
||||||
|
* Setable values
|
||||||
|
*/
|
||||||
|
int f_flags; /* SMBFS_RDD_ */
|
||||||
|
/*
|
||||||
|
* Return values
|
||||||
|
*/
|
||||||
|
struct smbfattr f_attr; /* current attributes */
|
||||||
|
char * f_name; /* current file name */
|
||||||
|
int f_nmlen; /* name len */
|
||||||
|
/*
|
||||||
|
* Internal variables
|
||||||
|
*/
|
||||||
|
int f_limit; /* maximum number of entries */
|
||||||
|
int f_attrmask; /* SMB_FA_ */
|
||||||
|
int f_wclen;
|
||||||
|
const char * f_wildcard;
|
||||||
|
struct smbnode* f_dnp;
|
||||||
|
struct smb_cred*f_scred;
|
||||||
|
struct smb_share *f_ssp;
|
||||||
|
union {
|
||||||
|
struct smb_rq * uf_rq;
|
||||||
|
struct smb_t2rq * uf_t2;
|
||||||
|
} f_urq;
|
||||||
|
int f_left; /* entries left */
|
||||||
|
int f_ecnt; /* entries left in the current reponse */
|
||||||
|
int f_eofs; /* entry offset in the parameter block */
|
||||||
|
u_char f_skey[SMB_SKEYLEN]; /* server side search context */
|
||||||
|
u_char f_fname[8 + 1 + 3 + 1]; /* common case for 8.3 filenames */
|
||||||
|
u_int16_t f_Sid;
|
||||||
|
u_int16_t f_infolevel;
|
||||||
|
int f_rnamelen;
|
||||||
|
char * f_rname; /* resume name/key */
|
||||||
|
int f_rnameofs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define f_rq f_urq.uf_rq
|
||||||
|
#define f_t2 f_urq.uf_t2
|
||||||
|
|
||||||
|
extern int smbfs_debuglevel;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* smb level
|
||||||
|
*/
|
||||||
|
int smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
|
||||||
|
off_t start, off_t end, struct smb_cred *scred);
|
||||||
|
int smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp,
|
||||||
|
struct smb_cred *scred);
|
||||||
|
int smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
|
||||||
|
struct smb_cred *scred);
|
||||||
|
int smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred);
|
||||||
|
|
||||||
|
int smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr,
|
||||||
|
struct timespec *mtime, struct smb_cred *scred);
|
||||||
|
int smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
|
||||||
|
struct timespec *atime, int attr, struct smb_cred *scred);
|
||||||
|
int smbfs_smb_setpattrNT(struct smbnode *np, u_int16_t attr,
|
||||||
|
struct timespec *mtime, struct timespec *atime, struct smb_cred *scred);
|
||||||
|
|
||||||
|
int smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
|
||||||
|
struct timespec *atime, struct smb_cred *scred);
|
||||||
|
int smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr,
|
||||||
|
struct timespec *mtime, struct timespec *atime, struct smb_cred *scred);
|
||||||
|
|
||||||
|
int smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred);
|
||||||
|
int smbfs_smb_close(struct smb_share *ssp, u_int16_t fid,
|
||||||
|
struct timespec *mtime, struct smb_cred *scred);
|
||||||
|
int smbfs_smb_create(struct smbnode *dnp, const char *name, int len,
|
||||||
|
struct smb_cred *scred);
|
||||||
|
int smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred);
|
||||||
|
int smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
|
||||||
|
const char *tname, int tnmlen, struct smb_cred *scred);
|
||||||
|
int smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
|
||||||
|
const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred);
|
||||||
|
int smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
|
||||||
|
struct smb_cred *scred);
|
||||||
|
int smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred);
|
||||||
|
int smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen,
|
||||||
|
int attr, struct smb_cred *scred, struct smbfs_fctx **ctxpp);
|
||||||
|
int smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred);
|
||||||
|
int smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred);
|
||||||
|
int smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp,
|
||||||
|
struct smbnode *dnp, const char *name, int nmlen);
|
||||||
|
int smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
|
||||||
|
struct smbfattr *fap, struct smb_cred *scred);
|
||||||
|
|
||||||
|
int smbfs_fname_tolocal(struct smb_vc *vcp, char *name, int nmlen, int caseopt);
|
||||||
|
|
||||||
|
void smb_time_local2server(struct timespec *tsp, int tzoff, u_long *seconds);
|
||||||
|
void smb_time_server2local(u_long seconds, int tzoff, struct timespec *tsp);
|
||||||
|
void smb_time_NT2local(int64_t nsec, int tzoff, struct timespec *tsp);
|
||||||
|
void smb_time_local2NT(struct timespec *tsp, int tzoff, int64_t *nsec);
|
||||||
|
void smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp,
|
||||||
|
u_int16_t *dtp, u_int8_t *dhp);
|
||||||
|
void smb_dos2unixtime (u_int dd, u_int dt, u_int dh, int tzoff, struct timespec *tsp);
|
||||||
|
|
||||||
|
#endif /* !_FS_SMBFS_SMBFS_SUBR_H_ */
|
513
sys/fs/smbfs/smbfs_vfsops.c
Normal file
513
sys/fs/smbfs/smbfs_vfsops.c
Normal file
@ -0,0 +1,513 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001, Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#include "opt_netsmb.h"
|
||||||
|
#ifndef NETSMB
|
||||||
|
#error "SMBFS requires option NETSMB"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/bio.h>
|
||||||
|
#include <sys/buf.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/vnode.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
#include <netsmb/smb_dev.h>
|
||||||
|
|
||||||
|
#include <fs/smbfs/smbfs.h>
|
||||||
|
#include <fs/smbfs/smbfs_node.h>
|
||||||
|
#include <fs/smbfs/smbfs_subr.h>
|
||||||
|
|
||||||
|
int smbfs_debuglevel = 0;
|
||||||
|
|
||||||
|
static int smbfs_version = SMBFS_VERSION;
|
||||||
|
|
||||||
|
#ifdef SMBFS_USEZONE
|
||||||
|
#include <vm/vm.h>
|
||||||
|
#include <vm/vm_extern.h>
|
||||||
|
#include <vm/vm_zone.h>
|
||||||
|
|
||||||
|
vm_zone_t smbfsmount_zone;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SYSCTL_NODE(_vfs, OID_AUTO, smbfs, CTLFLAG_RW, 0, "SMB/CIFS file system");
|
||||||
|
SYSCTL_INT(_vfs_smbfs, OID_AUTO, version, CTLFLAG_RD, &smbfs_version, 0, "");
|
||||||
|
SYSCTL_INT(_vfs_smbfs, OID_AUTO, debuglevel, CTLFLAG_RW, &smbfs_debuglevel, 0, "");
|
||||||
|
|
||||||
|
static MALLOC_DEFINE(M_SMBFSHASH, "SMBFS hash", "SMBFS hash table");
|
||||||
|
|
||||||
|
|
||||||
|
static int smbfs_mount(struct mount *, char *, caddr_t,
|
||||||
|
struct nameidata *, struct proc *);
|
||||||
|
static int smbfs_quotactl(struct mount *, int, uid_t, caddr_t, struct proc *);
|
||||||
|
static int smbfs_root(struct mount *, struct vnode **);
|
||||||
|
static int smbfs_start(struct mount *, int, struct proc *);
|
||||||
|
static int smbfs_statfs(struct mount *, struct statfs *, struct proc *);
|
||||||
|
static int smbfs_sync(struct mount *, int, struct ucred *, struct proc *);
|
||||||
|
static int smbfs_unmount(struct mount *, int, struct proc *);
|
||||||
|
static int smbfs_init(struct vfsconf *vfsp);
|
||||||
|
static int smbfs_uninit(struct vfsconf *vfsp);
|
||||||
|
|
||||||
|
#if __FreeBSD_version < 400009
|
||||||
|
static int smbfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp);
|
||||||
|
static int smbfs_fhtovp(struct mount *, struct fid *,
|
||||||
|
struct sockaddr *, struct vnode **, int *,
|
||||||
|
struct ucred **);
|
||||||
|
static int smbfs_vptofh(struct vnode *, struct fid *);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct vfsops smbfs_vfsops = {
|
||||||
|
smbfs_mount,
|
||||||
|
smbfs_start,
|
||||||
|
smbfs_unmount,
|
||||||
|
smbfs_root,
|
||||||
|
smbfs_quotactl,
|
||||||
|
smbfs_statfs,
|
||||||
|
smbfs_sync,
|
||||||
|
#if __FreeBSD_version > 400008
|
||||||
|
vfs_stdvget,
|
||||||
|
vfs_stdfhtovp, /* shouldn't happen */
|
||||||
|
vfs_stdcheckexp,
|
||||||
|
vfs_stdvptofh, /* shouldn't happen */
|
||||||
|
#else
|
||||||
|
smbfs_vget,
|
||||||
|
smbfs_fhtovp,
|
||||||
|
smbfs_vptofh,
|
||||||
|
#endif
|
||||||
|
smbfs_init,
|
||||||
|
smbfs_uninit,
|
||||||
|
#ifndef FB_RELENG3
|
||||||
|
vfs_stdextattrctl,
|
||||||
|
#else
|
||||||
|
#define M_USE_RESERVE M_KERNEL
|
||||||
|
&sysctl___vfs_smbfs
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
VFS_SET(smbfs_vfsops, smbfs, VFCF_NETWORK);
|
||||||
|
|
||||||
|
MODULE_DEPEND(smbfs, netsmb, NSMB_VERSION, NSMB_VERSION, NSMB_VERSION);
|
||||||
|
MODULE_DEPEND(smbfs, libiconv, 1, 1, 1);
|
||||||
|
|
||||||
|
int smbfs_pbuf_freecnt = -1; /* start out unlimited */
|
||||||
|
|
||||||
|
static int
|
||||||
|
smbfs_mount(struct mount *mp, char *path, caddr_t data,
|
||||||
|
struct nameidata *ndp, struct proc *p)
|
||||||
|
{
|
||||||
|
struct smbfs_args args; /* will hold data from mount request */
|
||||||
|
struct smbmount *smp = NULL;
|
||||||
|
struct smb_vc *vcp;
|
||||||
|
struct smb_share *ssp = NULL;
|
||||||
|
struct vnode *vp;
|
||||||
|
struct smb_cred scred;
|
||||||
|
#ifndef FB_CURRENT
|
||||||
|
size_t size;
|
||||||
|
#endif
|
||||||
|
int error;
|
||||||
|
char *pc, *pe;
|
||||||
|
|
||||||
|
if (data == NULL) {
|
||||||
|
printf("missing data argument\n");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
if (mp->mnt_flag & MNT_UPDATE) {
|
||||||
|
printf("MNT_UPDATE not implemented");
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
error = copyin(data, (caddr_t)&args, sizeof(struct smbfs_args));
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
if (args.version != SMBFS_VERSION) {
|
||||||
|
printf("mount version mismatch: kernel=%d, mount=%d\n",
|
||||||
|
SMBFS_VERSION, args.version);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
smb_makescred(&scred, p, p->p_ucred);
|
||||||
|
error = smb_dev2share(args.dev, SMBM_EXEC, &scred, &ssp);
|
||||||
|
if (error) {
|
||||||
|
printf("invalid device handle %d (%d)\n", args.dev, error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
vcp = SSTOVC(ssp);
|
||||||
|
smb_share_unlock(ssp, 0, p);
|
||||||
|
mp->mnt_stat.f_iosize = SSTOVC(ssp)->vc_txmax;
|
||||||
|
|
||||||
|
#ifdef SMBFS_USEZONE
|
||||||
|
smp = zalloc(smbfsmount_zone);
|
||||||
|
#else
|
||||||
|
MALLOC(smp, struct smbmount*, sizeof(*smp), M_SMBFSDATA, M_USE_RESERVE);
|
||||||
|
#endif
|
||||||
|
if (smp == NULL) {
|
||||||
|
printf("could not alloc smbmount\n");
|
||||||
|
error = ENOMEM;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
bzero(smp, sizeof(*smp));
|
||||||
|
mp->mnt_data = (qaddr_t)smp;
|
||||||
|
smp->sm_hash = hashinit(desiredvnodes, M_SMBFSHASH, &smp->sm_hashlen);
|
||||||
|
if (smp->sm_hash == NULL)
|
||||||
|
goto bad;
|
||||||
|
lockinit(&smp->sm_hashlock, PVFS, "smbfsh", 0, 0);
|
||||||
|
smp->sm_share = ssp;
|
||||||
|
smp->sm_root = NULL;
|
||||||
|
smp->sm_args = args;
|
||||||
|
smp->sm_caseopt = args.caseopt;
|
||||||
|
smp->sm_args.file_mode = (smp->sm_args.file_mode &
|
||||||
|
(S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
|
||||||
|
smp->sm_args.dir_mode = (smp->sm_args.dir_mode &
|
||||||
|
(S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
|
||||||
|
|
||||||
|
/* simple_lock_init(&smp->sm_npslock);*/
|
||||||
|
#ifndef FB_CURRENT
|
||||||
|
error = copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
|
||||||
|
#endif
|
||||||
|
pc = mp->mnt_stat.f_mntfromname;
|
||||||
|
pe = pc + sizeof(mp->mnt_stat.f_mntfromname);
|
||||||
|
bzero(pc, MNAMELEN);
|
||||||
|
*pc++ = '/';
|
||||||
|
*pc++ = '/';
|
||||||
|
pc=index(strncpy(pc, vcp->vc_username, pe - pc - 2), 0);
|
||||||
|
if (pc < pe-1) {
|
||||||
|
*(pc++) = '@';
|
||||||
|
pc = index(strncpy(pc, vcp->vc_srvname, pe - pc - 2), 0);
|
||||||
|
if (pc < pe - 1) {
|
||||||
|
*(pc++) = '/';
|
||||||
|
strncpy(pc, ssp->ss_name, pe - pc - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* protect against invalid mount points */
|
||||||
|
smp->sm_args.mount_point[sizeof(smp->sm_args.mount_point) - 1] = '\0';
|
||||||
|
vfs_getnewfsid(mp);
|
||||||
|
error = smbfs_root(mp, &vp);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
VOP_UNLOCK(vp, 0, p);
|
||||||
|
SMBVDEBUG("root.v_usecount = %d\n", vp->v_usecount);
|
||||||
|
|
||||||
|
#ifdef DIAGNOSTICS
|
||||||
|
SMBERROR("mp=%p\n", mp);
|
||||||
|
#endif
|
||||||
|
return error;
|
||||||
|
bad:
|
||||||
|
if (smp) {
|
||||||
|
if (smp->sm_hash)
|
||||||
|
free(smp->sm_hash, M_SMBFSHASH);
|
||||||
|
lockdestroy(&smp->sm_hashlock);
|
||||||
|
#ifdef SMBFS_USEZONE
|
||||||
|
zfree(smbfsmount_zone, smp);
|
||||||
|
#else
|
||||||
|
free(smp, M_SMBFSDATA);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (ssp)
|
||||||
|
smb_share_put(ssp, &scred);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unmount the filesystem described by mp. */
|
||||||
|
static int
|
||||||
|
smbfs_unmount(struct mount *mp, int mntflags, struct proc *p)
|
||||||
|
{
|
||||||
|
struct smbmount *smp = VFSTOSMBFS(mp);
|
||||||
|
struct vnode *vp;
|
||||||
|
struct smb_cred scred;
|
||||||
|
int error, flags;
|
||||||
|
|
||||||
|
SMBVDEBUG("smbfs_unmount: flags=%04x\n", mntflags);
|
||||||
|
flags = 0;
|
||||||
|
if (mntflags & MNT_FORCE)
|
||||||
|
flags |= FORCECLOSE;
|
||||||
|
error = VFS_ROOT(mp, &vp);
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
if (vp->v_usecount > 2) {
|
||||||
|
printf("smbfs_unmount: usecnt=%d\n", vp->v_usecount);
|
||||||
|
vput(vp);
|
||||||
|
return EBUSY;
|
||||||
|
}
|
||||||
|
error = vflush(mp, vp, flags);
|
||||||
|
if (error) {
|
||||||
|
vput(vp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
vput(vp);
|
||||||
|
vrele(vp);
|
||||||
|
vgone(vp);
|
||||||
|
smb_makescred(&scred, p, p->p_ucred);
|
||||||
|
smb_share_put(smp->sm_share, &scred);
|
||||||
|
mp->mnt_data = (qaddr_t)0;
|
||||||
|
|
||||||
|
if (smp->sm_hash)
|
||||||
|
free(smp->sm_hash, M_SMBFSHASH);
|
||||||
|
lockdestroy(&smp->sm_hashlock);
|
||||||
|
#ifdef SMBFS_USEZONE
|
||||||
|
zfree(smbfsmount_zone, smp);
|
||||||
|
#else
|
||||||
|
free(smp, M_SMBFSDATA);
|
||||||
|
#endif
|
||||||
|
mp->mnt_flag &= ~MNT_LOCAL;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return locked root vnode of a filesystem
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
smbfs_root(struct mount *mp, struct vnode **vpp)
|
||||||
|
{
|
||||||
|
struct smbmount *smp = VFSTOSMBFS(mp);
|
||||||
|
struct vnode *vp;
|
||||||
|
struct smbnode *np;
|
||||||
|
struct smbfattr fattr;
|
||||||
|
struct proc *p = curproc;
|
||||||
|
struct ucred *cred = p->p_ucred;
|
||||||
|
struct smb_cred scred;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (smp == NULL) {
|
||||||
|
SMBERROR("smp == NULL (bug in umount)\n");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
if (smp->sm_root) {
|
||||||
|
*vpp = SMBTOV(smp->sm_root);
|
||||||
|
return vget(*vpp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||||
|
}
|
||||||
|
smb_makescred(&scred, p, cred);
|
||||||
|
error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, &scred);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
error = smbfs_nget(mp, NULL, "TheRooT", 7, &fattr, &vp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
vp->v_flag |= VROOT;
|
||||||
|
np = VTOSMB(vp);
|
||||||
|
smp->sm_root = np;
|
||||||
|
*vpp = vp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vfs start routine, a no-op.
|
||||||
|
*/
|
||||||
|
/* ARGSUSED */
|
||||||
|
static int
|
||||||
|
smbfs_start(mp, flags, p)
|
||||||
|
struct mount *mp;
|
||||||
|
int flags;
|
||||||
|
struct proc *p;
|
||||||
|
{
|
||||||
|
SMBVDEBUG("flags=%04x\n", flags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do operations associated with quotas, not supported
|
||||||
|
*/
|
||||||
|
/* ARGSUSED */
|
||||||
|
static int
|
||||||
|
smbfs_quotactl(mp, cmd, uid, arg, p)
|
||||||
|
struct mount *mp;
|
||||||
|
int cmd;
|
||||||
|
uid_t uid;
|
||||||
|
caddr_t arg;
|
||||||
|
struct proc *p;
|
||||||
|
{
|
||||||
|
SMBVDEBUG("return EOPNOTSUPP\n");
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
|
int
|
||||||
|
smbfs_init(struct vfsconf *vfsp)
|
||||||
|
{
|
||||||
|
#ifndef SMP
|
||||||
|
int name[2];
|
||||||
|
int olen, ncpu, plen, error;
|
||||||
|
|
||||||
|
name[0] = CTL_HW;
|
||||||
|
name[1] = HW_NCPU;
|
||||||
|
error = kernel_sysctl(curproc, name, 2, &ncpu, &olen, NULL, 0, &plen);
|
||||||
|
if (error == 0 && ncpu > 1)
|
||||||
|
printf("warning: smbfs module compiled without SMP support.");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SMBFS_USEZONE
|
||||||
|
smbfsmount_zone = zinit("SMBFSMOUNT", sizeof(struct smbmount), 0, 0, 1);
|
||||||
|
#endif
|
||||||
|
smbfs_pbuf_freecnt = nswbuf / 2 + 1;
|
||||||
|
SMBVDEBUG("done.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*ARGSUSED*/
|
||||||
|
int
|
||||||
|
smbfs_uninit(struct vfsconf *vfsp)
|
||||||
|
{
|
||||||
|
|
||||||
|
SMBVDEBUG("done.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* smbfs_statfs call
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smbfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
|
||||||
|
{
|
||||||
|
struct smbmount *smp = VFSTOSMBFS(mp);
|
||||||
|
struct smbnode *np = smp->sm_root;
|
||||||
|
struct smb_share *ssp = smp->sm_share;
|
||||||
|
struct smb_cred scred;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
if (np == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
sbp->f_iosize = SSTOVC(ssp)->vc_txmax; /* optimal transfer block size */
|
||||||
|
sbp->f_spare2 = 0; /* placeholder */
|
||||||
|
smb_makescred(&scred, p, p->p_ucred);
|
||||||
|
|
||||||
|
if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
|
||||||
|
error = smbfs_smb_statfs2(ssp, sbp, &scred);
|
||||||
|
else
|
||||||
|
error = smbfs_smb_statfs(ssp, sbp, &scred);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
sbp->f_flags = 0; /* copy of mount exported flags */
|
||||||
|
if (sbp != &mp->mnt_stat) {
|
||||||
|
sbp->f_fsid = mp->mnt_stat.f_fsid; /* file system id */
|
||||||
|
sbp->f_owner = mp->mnt_stat.f_owner; /* user that mounted the filesystem */
|
||||||
|
sbp->f_type = mp->mnt_vfc->vfc_typenum; /* type of filesystem */
|
||||||
|
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||||
|
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||||
|
}
|
||||||
|
strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flush out the buffer cache
|
||||||
|
*/
|
||||||
|
/* ARGSUSED */
|
||||||
|
static int
|
||||||
|
smbfs_sync(mp, waitfor, cred, p)
|
||||||
|
struct mount *mp;
|
||||||
|
int waitfor;
|
||||||
|
struct ucred *cred;
|
||||||
|
struct proc *p;
|
||||||
|
{
|
||||||
|
struct vnode *vp;
|
||||||
|
int error, allerror = 0;
|
||||||
|
/*
|
||||||
|
* Force stale buffer cache information to be flushed.
|
||||||
|
*/
|
||||||
|
loop:
|
||||||
|
for (vp = mp->mnt_vnodelist.lh_first;
|
||||||
|
vp != NULL;
|
||||||
|
vp = vp->v_mntvnodes.le_next) {
|
||||||
|
/*
|
||||||
|
* If the vnode that we are about to sync is no longer
|
||||||
|
* associated with this mount point, start over.
|
||||||
|
*/
|
||||||
|
if (vp->v_mount != mp)
|
||||||
|
goto loop;
|
||||||
|
#ifndef FB_RELENG3
|
||||||
|
if (VOP_ISLOCKED(vp, NULL) || TAILQ_EMPTY(&vp->v_dirtyblkhd) ||
|
||||||
|
#else
|
||||||
|
if (VOP_ISLOCKED(vp) || TAILQ_EMPTY(&vp->v_dirtyblkhd) ||
|
||||||
|
#endif
|
||||||
|
waitfor == MNT_LAZY)
|
||||||
|
continue;
|
||||||
|
if (vget(vp, LK_EXCLUSIVE, p))
|
||||||
|
goto loop;
|
||||||
|
error = VOP_FSYNC(vp, cred, waitfor, p);
|
||||||
|
if (error)
|
||||||
|
allerror = error;
|
||||||
|
vput(vp);
|
||||||
|
}
|
||||||
|
return (allerror);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __FreeBSD_version < 400009
|
||||||
|
/*
|
||||||
|
* smbfs flat namespace lookup. Unsupported.
|
||||||
|
*/
|
||||||
|
/* ARGSUSED */
|
||||||
|
static int smbfs_vget(mp, ino, vpp)
|
||||||
|
struct mount *mp;
|
||||||
|
ino_t ino;
|
||||||
|
struct vnode **vpp;
|
||||||
|
{
|
||||||
|
return (EOPNOTSUPP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
|
static int smbfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
|
||||||
|
struct mount *mp;
|
||||||
|
struct fid *fhp;
|
||||||
|
struct sockaddr *nam;
|
||||||
|
struct vnode **vpp;
|
||||||
|
int *exflagsp;
|
||||||
|
struct ucred **credanonp;
|
||||||
|
{
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vnode pointer to File handle, should never happen either
|
||||||
|
*/
|
||||||
|
/* ARGSUSED */
|
||||||
|
static int
|
||||||
|
smbfs_vptofh(vp, fhp)
|
||||||
|
struct vnode *vp;
|
||||||
|
struct fid *fhp;
|
||||||
|
{
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __FreeBSD_version < 400009 */
|
1340
sys/fs/smbfs/smbfs_vnops.c
Normal file
1340
sys/fs/smbfs/smbfs_vnops.c
Normal file
File diff suppressed because it is too large
Load Diff
285
sys/kern/md4c.c
Normal file
285
sys/kern/md4c.c
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
|
||||||
|
|
||||||
|
License to copy and use this software is granted provided that it
|
||||||
|
is identified as the "RSA Data Security, Inc. MD4 Message-Digest
|
||||||
|
Algorithm" in all material mentioning or referencing this software
|
||||||
|
or this function.
|
||||||
|
|
||||||
|
License is also granted to make and use derivative works provided
|
||||||
|
that such works are identified as "derived from the RSA Data
|
||||||
|
Security, Inc. MD4 Message-Digest Algorithm" in all material
|
||||||
|
mentioning or referencing the derived work.
|
||||||
|
|
||||||
|
RSA Data Security, Inc. makes no representations concerning either
|
||||||
|
the merchantability of this software or the suitability of this
|
||||||
|
software for any particular purpose. It is provided "as is"
|
||||||
|
without express or implied warranty of any kind.
|
||||||
|
|
||||||
|
These notices must be retained in any copies of any part of this
|
||||||
|
documentation and/or software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/md4.h>
|
||||||
|
|
||||||
|
typedef unsigned char *POINTER;
|
||||||
|
typedef u_int16_t UINT2;
|
||||||
|
typedef u_int32_t UINT4;
|
||||||
|
|
||||||
|
#define PROTO_LIST(list) list
|
||||||
|
|
||||||
|
/* Constants for MD4Transform routine.
|
||||||
|
*/
|
||||||
|
#define S11 3
|
||||||
|
#define S12 7
|
||||||
|
#define S13 11
|
||||||
|
#define S14 19
|
||||||
|
#define S21 3
|
||||||
|
#define S22 5
|
||||||
|
#define S23 9
|
||||||
|
#define S24 13
|
||||||
|
#define S31 3
|
||||||
|
#define S32 9
|
||||||
|
#define S33 11
|
||||||
|
#define S34 15
|
||||||
|
|
||||||
|
static void MD4Transform PROTO_LIST ((UINT4 [4], const unsigned char [64]));
|
||||||
|
static void Encode PROTO_LIST
|
||||||
|
((unsigned char *, UINT4 *, unsigned int));
|
||||||
|
static void Decode PROTO_LIST
|
||||||
|
((UINT4 *, const unsigned char *, unsigned int));
|
||||||
|
|
||||||
|
static unsigned char PADDING[64] = {
|
||||||
|
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* F, G and H are basic MD4 functions.
|
||||||
|
*/
|
||||||
|
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||||
|
#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
|
||||||
|
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||||
|
|
||||||
|
/* ROTATE_LEFT rotates x left n bits.
|
||||||
|
*/
|
||||||
|
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||||
|
|
||||||
|
/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
|
||||||
|
/* Rotation is separate from addition to prevent recomputation */
|
||||||
|
#define FF(a, b, c, d, x, s) { \
|
||||||
|
(a) += F ((b), (c), (d)) + (x); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
}
|
||||||
|
#define GG(a, b, c, d, x, s) { \
|
||||||
|
(a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
}
|
||||||
|
#define HH(a, b, c, d, x, s) { \
|
||||||
|
(a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MD4 initialization. Begins an MD4 operation, writing a new context.
|
||||||
|
*/
|
||||||
|
void MD4Init (context)
|
||||||
|
MD4_CTX *context; /* context */
|
||||||
|
{
|
||||||
|
context->count[0] = context->count[1] = 0;
|
||||||
|
|
||||||
|
/* Load magic initialization constants.
|
||||||
|
*/
|
||||||
|
context->state[0] = 0x67452301;
|
||||||
|
context->state[1] = 0xefcdab89;
|
||||||
|
context->state[2] = 0x98badcfe;
|
||||||
|
context->state[3] = 0x10325476;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MD4 block update operation. Continues an MD4 message-digest
|
||||||
|
operation, processing another message block, and updating the
|
||||||
|
context.
|
||||||
|
*/
|
||||||
|
void MD4Update (context, input, inputLen)
|
||||||
|
MD4_CTX *context; /* context */
|
||||||
|
const unsigned char *input; /* input block */
|
||||||
|
unsigned int inputLen; /* length of input block */
|
||||||
|
{
|
||||||
|
unsigned int i, index, partLen;
|
||||||
|
|
||||||
|
/* Compute number of bytes mod 64 */
|
||||||
|
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
|
||||||
|
/* Update number of bits */
|
||||||
|
if ((context->count[0] += ((UINT4)inputLen << 3))
|
||||||
|
< ((UINT4)inputLen << 3))
|
||||||
|
context->count[1]++;
|
||||||
|
context->count[1] += ((UINT4)inputLen >> 29);
|
||||||
|
|
||||||
|
partLen = 64 - index;
|
||||||
|
/* Transform as many times as possible.
|
||||||
|
*/
|
||||||
|
if (inputLen >= partLen) {
|
||||||
|
bcopy(input, &context->buffer[index], partLen);
|
||||||
|
MD4Transform (context->state, context->buffer);
|
||||||
|
|
||||||
|
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||||
|
MD4Transform (context->state, &input[i]);
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
/* Buffer remaining input */
|
||||||
|
bcopy(&input[i], &context->buffer[index], inputLen-i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MD4 padding. */
|
||||||
|
void MD4Pad (context)
|
||||||
|
MD4_CTX *context; /* context */
|
||||||
|
{
|
||||||
|
unsigned char bits[8];
|
||||||
|
unsigned int index, padLen;
|
||||||
|
|
||||||
|
/* Save number of bits */
|
||||||
|
Encode (bits, context->count, 8);
|
||||||
|
|
||||||
|
/* Pad out to 56 mod 64.
|
||||||
|
*/
|
||||||
|
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
|
||||||
|
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||||
|
MD4Update (context, PADDING, padLen);
|
||||||
|
|
||||||
|
/* Append length (before padding) */
|
||||||
|
MD4Update (context, bits, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MD4 finalization. Ends an MD4 message-digest operation, writing the
|
||||||
|
the message digest and zeroizing the context.
|
||||||
|
*/
|
||||||
|
void MD4Final (digest, context)
|
||||||
|
unsigned char digest[16]; /* message digest */
|
||||||
|
MD4_CTX *context; /* context */
|
||||||
|
{
|
||||||
|
/* Do padding */
|
||||||
|
MD4Pad (context);
|
||||||
|
|
||||||
|
/* Store state in digest */
|
||||||
|
Encode (digest, context->state, 16);
|
||||||
|
|
||||||
|
/* Zeroize sensitive information.
|
||||||
|
*/
|
||||||
|
bzero((POINTER)context, sizeof (*context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MD4 basic transformation. Transforms state based on block.
|
||||||
|
*/
|
||||||
|
static void MD4Transform (state, block)
|
||||||
|
UINT4 state[4];
|
||||||
|
const unsigned char block[64];
|
||||||
|
{
|
||||||
|
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||||
|
|
||||||
|
Decode (x, block, 64);
|
||||||
|
|
||||||
|
/* Round 1 */
|
||||||
|
FF (a, b, c, d, x[ 0], S11); /* 1 */
|
||||||
|
FF (d, a, b, c, x[ 1], S12); /* 2 */
|
||||||
|
FF (c, d, a, b, x[ 2], S13); /* 3 */
|
||||||
|
FF (b, c, d, a, x[ 3], S14); /* 4 */
|
||||||
|
FF (a, b, c, d, x[ 4], S11); /* 5 */
|
||||||
|
FF (d, a, b, c, x[ 5], S12); /* 6 */
|
||||||
|
FF (c, d, a, b, x[ 6], S13); /* 7 */
|
||||||
|
FF (b, c, d, a, x[ 7], S14); /* 8 */
|
||||||
|
FF (a, b, c, d, x[ 8], S11); /* 9 */
|
||||||
|
FF (d, a, b, c, x[ 9], S12); /* 10 */
|
||||||
|
FF (c, d, a, b, x[10], S13); /* 11 */
|
||||||
|
FF (b, c, d, a, x[11], S14); /* 12 */
|
||||||
|
FF (a, b, c, d, x[12], S11); /* 13 */
|
||||||
|
FF (d, a, b, c, x[13], S12); /* 14 */
|
||||||
|
FF (c, d, a, b, x[14], S13); /* 15 */
|
||||||
|
FF (b, c, d, a, x[15], S14); /* 16 */
|
||||||
|
|
||||||
|
/* Round 2 */
|
||||||
|
GG (a, b, c, d, x[ 0], S21); /* 17 */
|
||||||
|
GG (d, a, b, c, x[ 4], S22); /* 18 */
|
||||||
|
GG (c, d, a, b, x[ 8], S23); /* 19 */
|
||||||
|
GG (b, c, d, a, x[12], S24); /* 20 */
|
||||||
|
GG (a, b, c, d, x[ 1], S21); /* 21 */
|
||||||
|
GG (d, a, b, c, x[ 5], S22); /* 22 */
|
||||||
|
GG (c, d, a, b, x[ 9], S23); /* 23 */
|
||||||
|
GG (b, c, d, a, x[13], S24); /* 24 */
|
||||||
|
GG (a, b, c, d, x[ 2], S21); /* 25 */
|
||||||
|
GG (d, a, b, c, x[ 6], S22); /* 26 */
|
||||||
|
GG (c, d, a, b, x[10], S23); /* 27 */
|
||||||
|
GG (b, c, d, a, x[14], S24); /* 28 */
|
||||||
|
GG (a, b, c, d, x[ 3], S21); /* 29 */
|
||||||
|
GG (d, a, b, c, x[ 7], S22); /* 30 */
|
||||||
|
GG (c, d, a, b, x[11], S23); /* 31 */
|
||||||
|
GG (b, c, d, a, x[15], S24); /* 32 */
|
||||||
|
|
||||||
|
/* Round 3 */
|
||||||
|
HH (a, b, c, d, x[ 0], S31); /* 33 */
|
||||||
|
HH (d, a, b, c, x[ 8], S32); /* 34 */
|
||||||
|
HH (c, d, a, b, x[ 4], S33); /* 35 */
|
||||||
|
HH (b, c, d, a, x[12], S34); /* 36 */
|
||||||
|
HH (a, b, c, d, x[ 2], S31); /* 37 */
|
||||||
|
HH (d, a, b, c, x[10], S32); /* 38 */
|
||||||
|
HH (c, d, a, b, x[ 6], S33); /* 39 */
|
||||||
|
HH (b, c, d, a, x[14], S34); /* 40 */
|
||||||
|
HH (a, b, c, d, x[ 1], S31); /* 41 */
|
||||||
|
HH (d, a, b, c, x[ 9], S32); /* 42 */
|
||||||
|
HH (c, d, a, b, x[ 5], S33); /* 43 */
|
||||||
|
HH (b, c, d, a, x[13], S34); /* 44 */
|
||||||
|
HH (a, b, c, d, x[ 3], S31); /* 45 */
|
||||||
|
HH (d, a, b, c, x[11], S32); /* 46 */
|
||||||
|
HH (c, d, a, b, x[ 7], S33); /* 47 */
|
||||||
|
HH (b, c, d, a, x[15], S34); /* 48 */
|
||||||
|
|
||||||
|
state[0] += a;
|
||||||
|
state[1] += b;
|
||||||
|
state[2] += c;
|
||||||
|
state[3] += d;
|
||||||
|
|
||||||
|
/* Zeroize sensitive information.
|
||||||
|
*/
|
||||||
|
bzero((POINTER)x, sizeof (x));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
|
||||||
|
a multiple of 4.
|
||||||
|
*/
|
||||||
|
static void Encode (output, input, len)
|
||||||
|
unsigned char *output;
|
||||||
|
UINT4 *input;
|
||||||
|
unsigned int len;
|
||||||
|
{
|
||||||
|
unsigned int i, j;
|
||||||
|
|
||||||
|
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||||
|
output[j] = (unsigned char)(input[i] & 0xff);
|
||||||
|
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
|
||||||
|
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
|
||||||
|
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
|
||||||
|
a multiple of 4.
|
||||||
|
*/
|
||||||
|
static void Decode (output, input, len)
|
||||||
|
|
||||||
|
UINT4 *output;
|
||||||
|
const unsigned char *input;
|
||||||
|
unsigned int len;
|
||||||
|
{
|
||||||
|
unsigned int i, j;
|
||||||
|
|
||||||
|
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||||
|
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
|
||||||
|
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
|
||||||
|
}
|
138
sys/netsmb/netbios.h
Normal file
138
sys/netsmb/netbios.h
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001 Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#ifndef _NETSMB_NETBIOS_H_
|
||||||
|
#define _NETSMB_NETBIOS_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* make this file dirty...
|
||||||
|
*/
|
||||||
|
#ifndef _NETINET_IN_H_
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _NETIPX_IPX_H_
|
||||||
|
#include <netipx/ipx.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define AF_NETBIOS AF_NS /* XXX: should go to socket.h */
|
||||||
|
#define PF_NETBIOS AF_NETBIOS
|
||||||
|
|
||||||
|
#define NBPROTO_TCPSSN 1 /* NETBIOS session over TCP */
|
||||||
|
#define NBPROTO_IPXSSN 11 /* NETBIOS over IPX */
|
||||||
|
|
||||||
|
#define NB_NAMELEN 16
|
||||||
|
#define NB_ENCNAMELEN NB_NAMELEN * 2
|
||||||
|
#define NB_MAXLABLEN 63
|
||||||
|
|
||||||
|
#define NB_MINSALEN (sizeof(struct sockaddr_nb))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* name types
|
||||||
|
*/
|
||||||
|
#define NBT_WKSTA 0x00
|
||||||
|
#define NBT_SERVER 0x20
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Session packet types
|
||||||
|
*/
|
||||||
|
#define NB_SSN_MESSAGE 0x0
|
||||||
|
#define NB_SSN_REQUEST 0x81
|
||||||
|
#define NB_SSN_POSRESP 0x82
|
||||||
|
#define NB_SSN_NEGRESP 0x83
|
||||||
|
#define NB_SSN_RTGRESP 0x84
|
||||||
|
#define NB_SSN_KEEPALIVE 0x85
|
||||||
|
|
||||||
|
/*
|
||||||
|
* resolver: Opcodes
|
||||||
|
*/
|
||||||
|
#define NBNS_OPCODE_QUERY 0x00
|
||||||
|
#define NBNS_OPCODE_REGISTER 0x05
|
||||||
|
#define NBNS_OPCODE_RELEASE 0x06
|
||||||
|
#define NBNS_OPCODE_WACK 0x07
|
||||||
|
#define NBNS_OPCODE_REFRESH 0x08
|
||||||
|
#define NBNS_OPCODE_RESPONSE 0x10 /* or'ed with other opcodes */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* resolver: NM_FLAGS
|
||||||
|
*/
|
||||||
|
#define NBNS_NMFLAG_BCAST 0x01
|
||||||
|
#define NBNS_NMFLAG_RA 0x08 /* recursion available */
|
||||||
|
#define NBNS_NMFLAG_RD 0x10 /* recursion desired */
|
||||||
|
#define NBNS_NMFLAG_TC 0x20 /* truncation occured */
|
||||||
|
#define NBNS_NMFLAG_AA 0x40 /* authoritative answer */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* resolver: Question types
|
||||||
|
*/
|
||||||
|
#define NBNS_QUESTION_TYPE_NB 0x0020
|
||||||
|
#define NBNS_QUESTION_TYPE_NBSTAT 0x0021
|
||||||
|
|
||||||
|
/*
|
||||||
|
* resolver: Question class
|
||||||
|
*/
|
||||||
|
#define NBNS_QUESTION_CLASS_IN 0x0001
|
||||||
|
|
||||||
|
/*
|
||||||
|
* resolver: Limits
|
||||||
|
*/
|
||||||
|
#define NBNS_MAXREDIRECTS 3 /* maximum number of accepted redirects */
|
||||||
|
#define NBDG_MAXSIZE 576 /* maximum nbns datagram size */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NETBIOS addressing
|
||||||
|
*/
|
||||||
|
union nb_tran {
|
||||||
|
struct sockaddr_in x_in;
|
||||||
|
struct sockaddr_ipx x_ipx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nb_name {
|
||||||
|
u_int nn_type;
|
||||||
|
u_char nn_name[NB_NAMELEN + 1];
|
||||||
|
u_char * nn_scope;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Socket address
|
||||||
|
*/
|
||||||
|
struct sockaddr_nb {
|
||||||
|
u_char snb_len;
|
||||||
|
u_char snb_family;
|
||||||
|
union nb_tran snb_tran; /* transport */
|
||||||
|
u_char snb_name[1 + NB_ENCNAMELEN + 1]; /* encoded */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define snb_addrin snb_tran.x_in
|
||||||
|
|
||||||
|
#endif /* !_NETSMB_NETBIOS_H_ */
|
388
sys/netsmb/smb.h
Normal file
388
sys/netsmb/smb.h
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001 Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common definintions and structures for SMB/CIFS protocol
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _NETSMB_SMB_H_
|
||||||
|
#define _NETSMB_SMB_H_
|
||||||
|
|
||||||
|
#define SMB_TCP_PORT 139
|
||||||
|
/*
|
||||||
|
* SMB dialects that we have to deal with.
|
||||||
|
*/
|
||||||
|
enum smb_dialects {
|
||||||
|
SMB_DIALECT_NONE,
|
||||||
|
SMB_DIALECT_CORE, /* PC NETWORK PROGRAM 1.0, PCLAN1.0 */
|
||||||
|
SMB_DIALECT_COREPLUS, /* MICROSOFT NETWORKS 1.03 */
|
||||||
|
SMB_DIALECT_LANMAN1_0, /* MICROSOFT NETWORKS 3.0, LANMAN1.0 */
|
||||||
|
SMB_DIALECT_LANMAN2_0, /* LM1.2X002, DOS LM1.2X002, Samba */
|
||||||
|
SMB_DIALECT_LANMAN2_1, /* DOS LANMAN2.1, LANMAN2.1 */
|
||||||
|
SMB_DIALECT_NTLM0_12 /* NT LM 0.12, Windows for Workgroups 3.1a,
|
||||||
|
* NT LANMAN 1.0 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Formats of data/string buffers
|
||||||
|
*/
|
||||||
|
#define SMB_DT_DATA 1
|
||||||
|
#define SMB_DT_DIALECT 2
|
||||||
|
#define SMB_DT_PATHNAME 3
|
||||||
|
#define SMB_DT_ASCII 4
|
||||||
|
#define SMB_DT_VARIABLE 5
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SMB header
|
||||||
|
*/
|
||||||
|
#define SMB_SIGNATURE "\xFFSMB"
|
||||||
|
#define SMB_SIGLEN 4
|
||||||
|
#define SMB_HDRMID(p) (*(u_short*)((u_char*)(p) + 30))
|
||||||
|
#define SMB_HDRLEN 32
|
||||||
|
/*
|
||||||
|
* bits in the smb_flags field
|
||||||
|
*/
|
||||||
|
#define SMB_FLAGS_CASELESS 0x08
|
||||||
|
#define SMB_FLAGS_SERVER_RESP 0x80 /* indicates a response */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bits in the smb_flags2 field
|
||||||
|
*/
|
||||||
|
#define SMB_FLAGS2_KNOWS_LONG_NAMES 0x0001
|
||||||
|
#define SMB_FLAGS2_KNOWS_EAS 0x0002 /* client know about EAs */
|
||||||
|
#define SMB_FLAGS2_SECURITY_SIGNATURE 0x0004 /* check SMB integrity */
|
||||||
|
#define SMB_FLAGS2_IS_LONG_NAME 0x0040 /* any path name is a long name */
|
||||||
|
#define SMB_FLAGS2_EXT_SEC 0x0800 /* client aware of Extended
|
||||||
|
* Security negotiation */
|
||||||
|
#define SMB_FLAGS2_DFS 0x1000 /* resolve paths in DFS */
|
||||||
|
#define SMB_FLAGS2_PAGING_IO 0x2000 /* for exec */
|
||||||
|
#define SMB_FLAGS2_ERR_STATUS 0x4000 /* 1 - status.status */
|
||||||
|
#define SMB_FLAGS2_UNICODE 0x8000 /* use Unicode for all strings */
|
||||||
|
|
||||||
|
#define SMB_UID_UNKNOWN 0xffff
|
||||||
|
#define SMB_TID_UNKNOWN 0xffff
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Security mode bits
|
||||||
|
*/
|
||||||
|
#define SMB_SM_USER 0x01 /* server in the user security mode */
|
||||||
|
#define SMB_SM_ENCRYPT 0x02 /* use challenge/responce */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NTLM capabilities
|
||||||
|
*/
|
||||||
|
#define SMB_CAP_RAW_MODE 0x0001
|
||||||
|
#define SMB_CAP_MPX_MODE 0x0002
|
||||||
|
#define SMB_CAP_UNICODE 0x0004
|
||||||
|
#define SMB_CAP_LARGE_FILES 0x0008 /* 64 bit offsets supported */
|
||||||
|
#define SMB_CAP_NT_SMBS 0x0010
|
||||||
|
#define SMB_CAP_NT_FIND 0x0200
|
||||||
|
#define SMB_CAP_EXT_SECURITY 0x80000000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File attributes
|
||||||
|
*/
|
||||||
|
#define SMB_FA_RDONLY 0x01
|
||||||
|
#define SMB_FA_HIDDEN 0x02
|
||||||
|
#define SMB_FA_SYSTEM 0x04
|
||||||
|
#define SMB_FA_VOLUME 0x08
|
||||||
|
#define SMB_FA_DIR 0x10
|
||||||
|
#define SMB_FA_ARCHIVE 0x20
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extended file attributes
|
||||||
|
*/
|
||||||
|
#define SMB_EFA_RDONLY 0x0001
|
||||||
|
#define SMB_EFA_HIDDEN 0x0002
|
||||||
|
#define SMB_EFA_SYSTEM 0x0004
|
||||||
|
#define SMB_EFA_ARCHIVE 0x0020
|
||||||
|
#define SMB_EFA_NORMAL 0x0080
|
||||||
|
#define SMB_EFA_TEMPORARY 0x0100
|
||||||
|
#define SMB_EFA_COMPRESSED 0x0800
|
||||||
|
#define SMB_EFA_POSIX_SEMANTICS 0x00100000
|
||||||
|
#define SMB_EFA_BACKUP_SEMANTICS 0x02000000
|
||||||
|
#define SMB_EFA_DELETE_ON_CLOSE 0x04000000
|
||||||
|
#define SMB_EFA_SEQUENTIAL_SCAN 0x08000000
|
||||||
|
#define SMB_EFA_RANDOM_ACCESS 0x10000000
|
||||||
|
#define SMB_EFA_NO_BUFFERING 0x20000000
|
||||||
|
#define SMB_EFA_WRITE_THROUGH 0x80000000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Access Mode Encoding
|
||||||
|
*/
|
||||||
|
#define SMB_AM_OPENREAD 0x0000
|
||||||
|
#define SMB_AM_OPENWRITE 0x0001
|
||||||
|
#define SMB_AM_OPENRW 0x0002
|
||||||
|
#define SMB_AM_OPENEXEC 0x0003
|
||||||
|
#define SMB_SM_COMPAT 0x0000
|
||||||
|
#define SMB_SM_EXCLUSIVE 0x0010
|
||||||
|
#define SMB_SM_DENYWRITE 0x0020
|
||||||
|
#define SMB_SM_DENYREADEXEC 0x0030
|
||||||
|
#define SMB_SM_DENYNONE 0x0040
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SMB commands
|
||||||
|
*/
|
||||||
|
#define SMB_COM_CREATE_DIRECTORY 0x00
|
||||||
|
#define SMB_COM_DELETE_DIRECTORY 0x01
|
||||||
|
#define SMB_COM_OPEN 0x02
|
||||||
|
#define SMB_COM_CREATE 0x03
|
||||||
|
#define SMB_COM_CLOSE 0x04
|
||||||
|
#define SMB_COM_FLUSH 0x05
|
||||||
|
#define SMB_COM_DELETE 0x06
|
||||||
|
#define SMB_COM_RENAME 0x07
|
||||||
|
#define SMB_COM_QUERY_INFORMATION 0x08
|
||||||
|
#define SMB_COM_SET_INFORMATION 0x09
|
||||||
|
#define SMB_COM_READ 0x0A
|
||||||
|
#define SMB_COM_WRITE 0x0B
|
||||||
|
#define SMB_COM_LOCK_BYTE_RANGE 0x0C
|
||||||
|
#define SMB_COM_UNLOCK_BYTE_RANGE 0x0D
|
||||||
|
#define SMB_COM_CREATE_TEMPORARY 0x0E
|
||||||
|
#define SMB_COM_CREATE_NEW 0x0F
|
||||||
|
#define SMB_COM_CHECK_DIRECTORY 0x10
|
||||||
|
#define SMB_COM_PROCESS_EXIT 0x11
|
||||||
|
#define SMB_COM_SEEK 0x12
|
||||||
|
#define SMB_COM_LOCK_AND_READ 0x13
|
||||||
|
#define SMB_COM_WRITE_AND_UNLOCK 0x14
|
||||||
|
#define SMB_COM_READ_RAW 0x1A
|
||||||
|
#define SMB_COM_READ_MPX 0x1B
|
||||||
|
#define SMB_COM_READ_MPX_SECONDARY 0x1C
|
||||||
|
#define SMB_COM_WRITE_RAW 0x1D
|
||||||
|
#define SMB_COM_WRITE_MPX 0x1E
|
||||||
|
#define SMB_COM_WRITE_COMPLETE 0x20
|
||||||
|
#define SMB_COM_SET_INFORMATION2 0x22
|
||||||
|
#define SMB_COM_QUERY_INFORMATION2 0x23
|
||||||
|
#define SMB_COM_LOCKING_ANDX 0x24
|
||||||
|
#define SMB_COM_TRANSACTION 0x25
|
||||||
|
#define SMB_COM_TRANSACTION_SECONDARY 0x26
|
||||||
|
#define SMB_COM_IOCTL 0x27
|
||||||
|
#define SMB_COM_IOCTL_SECONDARY 0x28
|
||||||
|
#define SMB_COM_COPY 0x29
|
||||||
|
#define SMB_COM_MOVE 0x2A
|
||||||
|
#define SMB_COM_ECHO 0x2B
|
||||||
|
#define SMB_COM_WRITE_AND_CLOSE 0x2C
|
||||||
|
#define SMB_COM_OPEN_ANDX 0x2D
|
||||||
|
#define SMB_COM_READ_ANDX 0x2E
|
||||||
|
#define SMB_COM_WRITE_ANDX 0x2F
|
||||||
|
#define SMB_COM_CLOSE_AND_TREE_DISC 0x31
|
||||||
|
#define SMB_COM_TRANSACTION2 0x32
|
||||||
|
#define SMB_COM_TRANSACTION2_SECONDARY 0x33
|
||||||
|
#define SMB_COM_FIND_CLOSE2 0x34
|
||||||
|
#define SMB_COM_FIND_NOTIFY_CLOSE 0x35
|
||||||
|
#define SMB_COM_TREE_CONNECT 0x70
|
||||||
|
#define SMB_COM_TREE_DISCONNECT 0x71
|
||||||
|
#define SMB_COM_NEGOTIATE 0x72
|
||||||
|
#define SMB_COM_SESSION_SETUP_ANDX 0x73
|
||||||
|
#define SMB_COM_LOGOFF_ANDX 0x74
|
||||||
|
#define SMB_COM_TREE_CONNECT_ANDX 0x75
|
||||||
|
#define SMB_COM_QUERY_INFORMATION_DISK 0x80
|
||||||
|
#define SMB_COM_SEARCH 0x81
|
||||||
|
#define SMB_COM_FIND 0x82
|
||||||
|
#define SMB_COM_FIND_UNIQUE 0x83
|
||||||
|
#define SMB_COM_NT_TRANSACT 0xA0
|
||||||
|
#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
|
||||||
|
#define SMB_COM_NT_CREATE_ANDX 0xA2
|
||||||
|
#define SMB_COM_NT_CANCEL 0xA4
|
||||||
|
#define SMB_COM_OPEN_PRINT_FILE 0xC0
|
||||||
|
#define SMB_COM_WRITE_PRINT_FILE 0xC1
|
||||||
|
#define SMB_COM_CLOSE_PRINT_FILE 0xC2
|
||||||
|
#define SMB_COM_GET_PRINT_QUEUE 0xC3
|
||||||
|
#define SMB_COM_READ_BULK 0xD8
|
||||||
|
#define SMB_COM_WRITE_BULK 0xD9
|
||||||
|
#define SMB_COM_WRITE_BULK_DATA 0xDA
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TRANS2 commands
|
||||||
|
*/
|
||||||
|
#define SMB_TRANS2_OPEN2 0x00
|
||||||
|
#define SMB_TRANS2_FIND_FIRST2 0x01
|
||||||
|
#define SMB_TRANS2_FIND_NEXT2 0x02
|
||||||
|
#define SMB_TRANS2_QUERY_FS_INFORMATION 0x03
|
||||||
|
#define SMB_TRANS2_QUERY_PATH_INFORMATION 0x05
|
||||||
|
#define SMB_TRANS2_SET_PATH_INFORMATION 0x06
|
||||||
|
#define SMB_TRANS2_QUERY_FILE_INFORMATION 0x07
|
||||||
|
#define SMB_TRANS2_SET_FILE_INFORMATION 0x08
|
||||||
|
#define SMB_TRANS2_FSCTL 0x09
|
||||||
|
#define SMB_TRANS2_IOCTL2 0x0A
|
||||||
|
#define SMB_TRANS2_FIND_NOTIFY_FIRST 0x0B
|
||||||
|
#define SMB_TRANS2_FIND_NOTIFY_NEXT 0x0C
|
||||||
|
#define SMB_TRANS2_CREATE_DIRECTORY 0x0D
|
||||||
|
#define SMB_TRANS2_SESSION_SETUP 0x0E
|
||||||
|
#define SMB_TRANS2_GET_DFS_REFERRAL 0x10
|
||||||
|
#define SMB_TRANS2_REPORT_DFS_INCONSISTENCY 0x11
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SMB_TRANS2_QUERY_FS_INFORMATION levels
|
||||||
|
*/
|
||||||
|
#define SMB_INFO_ALLOCATION 1
|
||||||
|
#define SMB_INFO_VOLUME 2
|
||||||
|
#define SMB_QUERY_FS_VOLUME_INFO 0x102
|
||||||
|
#define SMB_QUERY_FS_SIZE_INFO 0x103
|
||||||
|
#define SMB_QUERY_FS_DEVICE_INFO 0x104
|
||||||
|
#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SMB_TRANS2_FIND_FIRST2 information levels
|
||||||
|
*/
|
||||||
|
#define SMB_INFO_STANDARD 1
|
||||||
|
#define SMB_INFO_QUERY_EA_SIZE 2
|
||||||
|
#define SMB_INFO_QUERY_EAS_FROM_LIST 3
|
||||||
|
#define SMB_FIND_FILE_DIRECTORY_INFO 0x101
|
||||||
|
#define SMB_FIND_FULL_DIRECTORY_INFO 0x102
|
||||||
|
#define SMB_FIND_FILE_NAMES_INFO 0x103
|
||||||
|
#define SMB_FIND_BOTH_DIRECTORY_INFO 0x104
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set PATH/FILE information levels
|
||||||
|
*/
|
||||||
|
#define SMB_SET_FILE_BASIC_INFO 0x101
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LOCKING_ANDX LockType flags
|
||||||
|
*/
|
||||||
|
#define SMB_LOCKING_ANDX_SHARED_LOCK 0x01
|
||||||
|
#define SMB_LOCKING_ANDX_OPLOCK_RELEASE 0x02
|
||||||
|
#define SMB_LOCKING_ANDX_CHANGE_LOCKTYPE 0x04
|
||||||
|
#define SMB_LOCKING_ANDX_CANCEL_LOCK 0x08
|
||||||
|
#define SMB_LOCKING_ANDX_LARGE_FILES 0x10
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some names length limitations. Some of them aren't declared by specs,
|
||||||
|
* but we need reasonable limits.
|
||||||
|
*/
|
||||||
|
#define SMB_MAXSRVNAMELEN 15 /* NetBIOS limit */
|
||||||
|
#define SMB_MAXUSERNAMELEN 128
|
||||||
|
#define SMB_MAXPASSWORDLEN 128
|
||||||
|
#define SMB_MAXSHARENAMELEN 128
|
||||||
|
#define SMB_MAXPKTLEN 0x1FFFF
|
||||||
|
#define SMB_MAXCHALLENGELEN 8
|
||||||
|
#define SMB_MAXFNAMELEN 255 /* Keep in sync with MAXNAMLEN */
|
||||||
|
|
||||||
|
#define SMB_MAXRCN 3 /* number of reconnect attempts */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Error classes
|
||||||
|
*/
|
||||||
|
#define SMBSUCCESS 0x00
|
||||||
|
#define ERRDOS 0x01
|
||||||
|
#define ERRSRV 0x02
|
||||||
|
#define ERRHRD 0x03 /* Error is an hardware error. */
|
||||||
|
#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Error codes for the ERRDOS class
|
||||||
|
*/
|
||||||
|
#define ERRbadfunc 1 /* Invalid function */
|
||||||
|
#define ERRbadfile 2 /* File not found (last component) */
|
||||||
|
#define ERRbadpath 3 /* Directory invalid */
|
||||||
|
#define ERRnofids 4 /* Too many open files */
|
||||||
|
#define ERRnoaccess 5 /* Access denied */
|
||||||
|
#define ERRbadfid 6 /* Invalid file handle */
|
||||||
|
#define ERRbadmcb 7 /* Memory control blocks destroyed (huh ?) */
|
||||||
|
#define ERRnomem 8 /* Insufficient memory */
|
||||||
|
#define ERRbadmem 9 /* Invalid memory block address */
|
||||||
|
#define ERRbadenv 10 /* Invalid environment */
|
||||||
|
#define ERRbadformat 11 /* Invalid format */
|
||||||
|
#define ERRbadaccess 12 /* Invalid open mode */
|
||||||
|
#define ERRbaddata 13 /* Invalid data */
|
||||||
|
#define ERRbaddrive 15 /* Invalid drive specified */
|
||||||
|
#define ERRremcd 16 /* An attempt to delete current directory */
|
||||||
|
#define ERRdiffdevice 17 /* cross fs rename/move */
|
||||||
|
#define ERRnofiles 18 /* no more files found in file search */
|
||||||
|
#define ERRbadshare 32 /* Share mode can't be granted */
|
||||||
|
#define ERRlock 33 /* A lock request conflicts with existing lock */
|
||||||
|
#define ERRfilexists 80 /* The file named in the request already exists */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Error codes for the ERRSRV class
|
||||||
|
*/
|
||||||
|
#define ERRerror 1 /* Non-specific error code */
|
||||||
|
#define ERRbadpw 2 /* Bad password */
|
||||||
|
#define ERRaccess 4 /* The client doesn't have enough access rights */
|
||||||
|
#define ERRinvnid 5 /* The Tid specified in a command is invalid */
|
||||||
|
#define ERRinvnetname 6 /* Invalid server name in the tree connect */
|
||||||
|
#define ERRinvdevice 7 /* Printer and not printer devices are mixed */
|
||||||
|
#define ERRqfull 49 /* Print queue full */
|
||||||
|
#define ERRqtoobig 50 /* Print queue full - no space */
|
||||||
|
#define ERRinvpfid 52 /* Invalid print file FID */
|
||||||
|
#define ERRsmbcmd 64 /* The server did not recognise the command */
|
||||||
|
#define ERRsrverror 65 /* The server encountered and internal error */
|
||||||
|
#define ERRfilespecs 67 /* The Fid and path name contains an invalid combination */
|
||||||
|
#define ERRbadpermits 69 /* Access mode invalid */
|
||||||
|
#define ERRsetattrmode 71 /* Attribute mode invalid */
|
||||||
|
#define ERRpaused 81 /* Server is paused */
|
||||||
|
#define ERRmsgoff 82 /* Not receiving messages */
|
||||||
|
#define ERRnoroom 83 /* No room to buffer message */
|
||||||
|
#define ERRrmuns 87 /* Too many remote user names */
|
||||||
|
#define ERRtimeout 88 /* Operation timed out */
|
||||||
|
#define ERRnoresource 89 /* No resources currently available for request */
|
||||||
|
#define ERRtoomanyuids 90 /* Too many UIDs active on this session */
|
||||||
|
#define ERRbaduid 91 /* The UID is not known in this session */
|
||||||
|
#define ERRusempx 250 /* Temporarily unable to support Raw, use MPX mode */
|
||||||
|
#define ERRusestd 251 /* Temporarily unable to support Raw, use stdandard r/w */
|
||||||
|
#define ERRcontmpx 252 /* Continue in MPX mode */
|
||||||
|
#define ERRnosupport 65535 /* Invalid function */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Error codes for the ERRHRD class
|
||||||
|
*/
|
||||||
|
#define ERRnowrite 19 /* write protected media */
|
||||||
|
#define ERRbadunit 20 /* Unknown unit */
|
||||||
|
#define ERRnotready 21 /* Drive not ready */
|
||||||
|
#define ERRbadcmd 22 /* Unknown command */
|
||||||
|
#define ERRdata 23 /* Data error (CRC) */
|
||||||
|
#define ERRbadreq 24 /* Bad request structure length */
|
||||||
|
#define ERRseek 25 /* Seek error */
|
||||||
|
#define ERRbadmedia 26 /* Unknown media type */
|
||||||
|
#define ERRbadsector 27 /* Sector not found */
|
||||||
|
#define ERRnopaper 28 /* Printer out of paper */
|
||||||
|
#define ERRwrite 29 /* Write fault */
|
||||||
|
#define ERRread 30 /* Read fault */
|
||||||
|
#define ERRgeneral 31 /* General failure */
|
||||||
|
#define ERRbadshare 32 /* A open conflicts with an existing open */
|
||||||
|
#define ERRlock 33 /* lock/unlock conflict */
|
||||||
|
#define ERRwrongdisk 34 /* The wrong disk was found in a drive */
|
||||||
|
#define ERRFCBunavail 35 /* No FCBs available */
|
||||||
|
#define ERRsharebufexc 36 /* A sharing buffer has been exceeded */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RAP error codes (it seems that they returned not only by RAP)
|
||||||
|
*/
|
||||||
|
#define SMB_ERROR_ACCESS_DENIED 5
|
||||||
|
#define SMB_ERROR_NETWORK_ACCESS_DENIED 65
|
||||||
|
#define SMB_ERROR_MORE_DATA 234
|
||||||
|
|
||||||
|
typedef u_int16_t smbfh;
|
||||||
|
|
||||||
|
#endif /* _NETSMB_SMB_H_ */
|
874
sys/netsmb/smb_conn.c
Normal file
874
sys/netsmb/smb_conn.c
Normal file
@ -0,0 +1,874 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001 Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Connection engine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/socketvar.h>
|
||||||
|
|
||||||
|
#include <sys/iconv.h>
|
||||||
|
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_tran.h>
|
||||||
|
#include <netsmb/smb_trantcp.h>
|
||||||
|
|
||||||
|
static struct smb_connobj smb_vclist;
|
||||||
|
static int smb_vcnext = 1; /* next unique id for VC */
|
||||||
|
|
||||||
|
extern struct linker_set sysctl_net_smb;
|
||||||
|
|
||||||
|
SYSCTL_NODE(_net, OID_AUTO, smb, CTLFLAG_RW, NULL, "SMB protocol");
|
||||||
|
|
||||||
|
MALLOC_DEFINE(M_SMBCONN, "SMB conn", "SMB connection");
|
||||||
|
|
||||||
|
static void smb_co_init(struct smb_connobj *cp, int level, char *objname,
|
||||||
|
struct proc *p);
|
||||||
|
static void smb_co_done(struct smb_connobj *cp);
|
||||||
|
static int smb_co_lockstatus(struct smb_connobj *cp, struct proc *p);
|
||||||
|
|
||||||
|
static int smb_vc_disconnect(struct smb_vc *vcp);
|
||||||
|
static void smb_vc_free(struct smb_connobj *cp);
|
||||||
|
static void smb_vc_gone(struct smb_connobj *cp, struct smb_cred *scred);
|
||||||
|
static smb_co_free_t smb_share_free;
|
||||||
|
static smb_co_gone_t smb_share_gone;
|
||||||
|
|
||||||
|
static int smb_sysctl_treedump(SYSCTL_HANDLER_ARGS);
|
||||||
|
|
||||||
|
SYSCTL_PROC(_net_smb, OID_AUTO, treedump, CTLFLAG_RD | CTLTYPE_OPAQUE,
|
||||||
|
NULL, 0, smb_sysctl_treedump, "S,treedump", "Requester tree");
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_sm_init(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
smb_co_init(&smb_vclist, SMBL_SM, "smbsm", curproc);
|
||||||
|
smb_co_unlock(&smb_vclist, 0, curproc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_sm_done(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* XXX: hold the mutex */
|
||||||
|
if (smb_vclist.co_usecount > 1) {
|
||||||
|
SMBERROR("%d connections still active\n", smb_vclist.co_usecount - 1);
|
||||||
|
return EBUSY;
|
||||||
|
}
|
||||||
|
smb_co_done(&smb_vclist);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_sm_lockvclist(int flags, struct proc *p)
|
||||||
|
{
|
||||||
|
|
||||||
|
return smb_co_lock(&smb_vclist, flags | LK_CANRECURSE, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_sm_unlockvclist(struct proc *p)
|
||||||
|
{
|
||||||
|
|
||||||
|
smb_co_unlock(&smb_vclist, LK_RELEASE, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_sm_lookupint(struct smb_vcspec *vcspec, struct smb_sharespec *shspec,
|
||||||
|
struct smb_cred *scred, struct smb_vc **vcpp)
|
||||||
|
{
|
||||||
|
struct proc *p = scred->scr_p;
|
||||||
|
struct smb_vc *vcp;
|
||||||
|
int exact = 1;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
vcspec->shspec = shspec;
|
||||||
|
error = ENOENT;
|
||||||
|
SMBCO_FOREACH((struct smb_connobj*)vcp, &smb_vclist) {
|
||||||
|
error = smb_vc_lock(vcp, LK_EXCLUSIVE, p);
|
||||||
|
if (error)
|
||||||
|
continue;
|
||||||
|
itry {
|
||||||
|
if ((vcp->obj.co_flags & SMBV_PRIVATE) ||
|
||||||
|
!CONNADDREQ(vcp->vc_paddr, vcspec->sap) ||
|
||||||
|
strcmp(vcp->vc_username, vcspec->username) != 0)
|
||||||
|
ithrow(1);
|
||||||
|
if (vcspec->owner != SMBM_ANY_OWNER) {
|
||||||
|
if (vcp->vc_uid != vcspec->owner)
|
||||||
|
ithrow(1);
|
||||||
|
} else
|
||||||
|
exact = 0;
|
||||||
|
if (vcspec->group != SMBM_ANY_GROUP) {
|
||||||
|
if (vcp->vc_grp != vcspec->group)
|
||||||
|
ithrow(1);
|
||||||
|
} else
|
||||||
|
exact = 0;
|
||||||
|
|
||||||
|
if (vcspec->mode & SMBM_EXACT) {
|
||||||
|
if (!exact ||
|
||||||
|
(vcspec->mode & SMBM_MASK) != vcp->vc_mode)
|
||||||
|
ithrow(1);
|
||||||
|
}
|
||||||
|
if (smb_vc_access(vcp, scred, vcspec->mode) != 0)
|
||||||
|
ithrow(1);
|
||||||
|
vcspec->ssp = NULL;
|
||||||
|
if (shspec)
|
||||||
|
ithrow(smb_vc_lookupshare(vcp, shspec, scred, &vcspec->ssp));
|
||||||
|
error = 0;
|
||||||
|
break;
|
||||||
|
} icatch(error) {
|
||||||
|
smb_vc_unlock(vcp, 0, p);
|
||||||
|
} ifinally {
|
||||||
|
} iendtry;
|
||||||
|
if (error == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (vcp) {
|
||||||
|
smb_vc_ref(vcp, p);
|
||||||
|
*vcpp = vcp;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_sm_lookup(struct smb_vcspec *vcspec, struct smb_sharespec *shspec,
|
||||||
|
struct smb_cred *scred, struct smb_vc **vcpp)
|
||||||
|
{
|
||||||
|
struct proc *p = scred->scr_p;
|
||||||
|
struct smb_vc *vcp;
|
||||||
|
struct smb_share *ssp = NULL;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
*vcpp = vcp = NULL;
|
||||||
|
|
||||||
|
error = smb_sm_lockvclist(LK_EXCLUSIVE, p);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
error = smb_sm_lookupint(vcspec, shspec, scred, vcpp);
|
||||||
|
if (error == 0 || (vcspec->flags & SMBV_CREATE) == 0) {
|
||||||
|
smb_sm_unlockvclist(p);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
error = smb_sm_lookupint(vcspec, NULL, scred, &vcp);
|
||||||
|
if (error) {
|
||||||
|
error = smb_vc_create(vcspec, scred, &vcp);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
error = smb_vc_connect(vcp, scred);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (shspec == NULL)
|
||||||
|
goto out;
|
||||||
|
error = smb_share_create(vcp, shspec, scred, &ssp);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
error = smb_smb_treeconnect(ssp, scred);
|
||||||
|
if (error == 0)
|
||||||
|
vcspec->ssp = ssp;
|
||||||
|
else
|
||||||
|
smb_share_put(ssp, scred);
|
||||||
|
out:
|
||||||
|
smb_sm_unlockvclist(p);
|
||||||
|
if (error == 0)
|
||||||
|
*vcpp = vcp;
|
||||||
|
else if (vcp)
|
||||||
|
smb_vc_put(vcp, scred);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common code for connection object
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
smb_co_init(struct smb_connobj *cp, int level, char *objname, struct proc *p)
|
||||||
|
{
|
||||||
|
SLIST_INIT(&cp->co_children);
|
||||||
|
smb_sl_init(&cp->co_interlock, objname);
|
||||||
|
lockinit(&cp->co_lock, PZERO, objname, 0, 0);
|
||||||
|
cp->co_level = level;
|
||||||
|
cp->co_usecount = 1;
|
||||||
|
KASSERT(smb_co_lock(cp, LK_EXCLUSIVE, p) == 0, ("smb_co_init: lock failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_co_done(struct smb_connobj *cp)
|
||||||
|
{
|
||||||
|
smb_sl_destroy(&cp->co_interlock);
|
||||||
|
lockdestroy(&cp->co_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_co_gone(struct smb_connobj *cp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_connobj *parent;
|
||||||
|
|
||||||
|
if (cp->co_gone)
|
||||||
|
cp->co_gone(cp, scred);
|
||||||
|
parent = cp->co_parent;
|
||||||
|
if (parent) {
|
||||||
|
smb_co_lock(parent, LK_EXCLUSIVE, scred->scr_p);
|
||||||
|
SLIST_REMOVE(&parent->co_children, cp, smb_connobj, co_next);
|
||||||
|
smb_co_put(parent, scred);
|
||||||
|
}
|
||||||
|
if (cp->co_free)
|
||||||
|
cp->co_free(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_co_ref(struct smb_connobj *cp, struct proc *p)
|
||||||
|
{
|
||||||
|
|
||||||
|
SMB_CO_LOCK(cp);
|
||||||
|
cp->co_usecount++;
|
||||||
|
SMB_CO_UNLOCK(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_co_rele(struct smb_connobj *cp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct proc *p = scred->scr_p;
|
||||||
|
|
||||||
|
SMB_CO_LOCK(cp);
|
||||||
|
if (cp->co_usecount > 1) {
|
||||||
|
cp->co_usecount--;
|
||||||
|
SMB_CO_UNLOCK(cp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cp->co_usecount == 0) {
|
||||||
|
SMBERROR("negative use_count for object %d", cp->co_level);
|
||||||
|
SMB_CO_UNLOCK(cp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cp->co_usecount--;
|
||||||
|
cp->co_flags |= SMBO_GONE;
|
||||||
|
|
||||||
|
lockmgr(&cp->co_lock, LK_DRAIN | LK_INTERLOCK, &cp->co_interlock, p);
|
||||||
|
smb_co_gone(cp, scred);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_co_get(struct smb_connobj *cp, int flags, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if ((flags & LK_INTERLOCK) == 0)
|
||||||
|
SMB_CO_LOCK(cp);
|
||||||
|
cp->co_usecount++;
|
||||||
|
error = smb_co_lock(cp, flags | LK_INTERLOCK, scred->scr_p);
|
||||||
|
if (error) {
|
||||||
|
SMB_CO_LOCK(cp);
|
||||||
|
cp->co_usecount--;
|
||||||
|
SMB_CO_UNLOCK(cp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_co_put(struct smb_connobj *cp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct proc *p = scred->scr_p;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
flags = LK_RELEASE;
|
||||||
|
SMB_CO_LOCK(cp);
|
||||||
|
if (cp->co_usecount > 1) {
|
||||||
|
cp->co_usecount--;
|
||||||
|
} else if (cp->co_usecount == 1) {
|
||||||
|
cp->co_usecount--;
|
||||||
|
cp->co_flags |= SMBO_GONE;
|
||||||
|
flags = LK_DRAIN;
|
||||||
|
} else {
|
||||||
|
SMBERROR("negative usecount");
|
||||||
|
}
|
||||||
|
lockmgr(&cp->co_lock, LK_RELEASE | LK_INTERLOCK, &cp->co_interlock, p);
|
||||||
|
if ((cp->co_flags & SMBO_GONE) == 0)
|
||||||
|
return;
|
||||||
|
lockmgr(&cp->co_lock, LK_DRAIN, NULL, p);
|
||||||
|
smb_co_gone(cp, scred);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_co_lockstatus(struct smb_connobj *cp, struct proc *p)
|
||||||
|
{
|
||||||
|
return lockstatus(&cp->co_lock, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_co_lock(struct smb_connobj *cp, int flags, struct proc *p)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (cp->co_flags & SMBO_GONE)
|
||||||
|
return EINVAL;
|
||||||
|
if ((flags & LK_TYPE_MASK) == 0)
|
||||||
|
flags |= LK_EXCLUSIVE;
|
||||||
|
if (smb_co_lockstatus(cp, p) == LK_EXCLUSIVE &&
|
||||||
|
(flags & LK_CANRECURSE) == 0) {
|
||||||
|
SMBERROR("recursive lock for object %d\n", cp->co_level);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return lockmgr(&cp->co_lock, flags, &cp->co_interlock, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_co_unlock(struct smb_connobj *cp, int flags, struct proc *p)
|
||||||
|
{
|
||||||
|
(void)lockmgr(&cp->co_lock, flags | LK_RELEASE, &cp->co_interlock, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_co_addchild(struct smb_connobj *parent, struct smb_connobj *child)
|
||||||
|
{
|
||||||
|
KASSERT(smb_co_lockstatus(parent, curproc) == LK_EXCLUSIVE, ("smb_co_addchild: parent not locked"));
|
||||||
|
KASSERT(smb_co_lockstatus(child, curproc) == LK_EXCLUSIVE, ("smb_co_addchild: child not locked"));
|
||||||
|
|
||||||
|
smb_co_ref(parent, curproc);
|
||||||
|
SLIST_INSERT_HEAD(&parent->co_children, child, co_next);
|
||||||
|
child->co_parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Session implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_vc_create(struct smb_vcspec *vcspec,
|
||||||
|
struct smb_cred *scred, struct smb_vc **vcpp)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp;
|
||||||
|
struct proc *p = scred->scr_p;
|
||||||
|
struct ucred *cred = scred->scr_cred;
|
||||||
|
uid_t uid = vcspec->owner;
|
||||||
|
gid_t gid = vcspec->group;
|
||||||
|
uid_t realuid = cred->cr_uid;
|
||||||
|
char *domain = vcspec->domain;
|
||||||
|
int error, isroot;
|
||||||
|
|
||||||
|
isroot = smb_suser(cred) == 0;
|
||||||
|
/*
|
||||||
|
* Only superuser can create VCs with different uid and gid
|
||||||
|
*/
|
||||||
|
if (uid != SMBM_ANY_OWNER && uid != realuid && !isroot)
|
||||||
|
return EPERM;
|
||||||
|
if (gid != SMBM_ANY_GROUP && !groupmember(gid, cred) && !isroot)
|
||||||
|
return EPERM;
|
||||||
|
|
||||||
|
vcp = smb_zmalloc(sizeof(*vcp), M_SMBCONN, M_WAITOK);
|
||||||
|
smb_co_init(VCTOCP(vcp), SMBL_VC, "smb_vc", p);
|
||||||
|
vcp->obj.co_free = smb_vc_free;
|
||||||
|
vcp->obj.co_gone = smb_vc_gone;
|
||||||
|
vcp->vc_number = smb_vcnext++;
|
||||||
|
vcp->vc_timo = SMB_DEFRQTIMO;
|
||||||
|
vcp->vc_smbuid = SMB_UID_UNKNOWN;
|
||||||
|
vcp->vc_mode = vcspec->rights & SMBM_MASK;
|
||||||
|
vcp->obj.co_flags = vcspec->flags & (SMBV_PRIVATE | SMBV_SINGLESHARE);
|
||||||
|
vcp->vc_tdesc = &smb_tran_nbtcp_desc;
|
||||||
|
|
||||||
|
if (uid == SMBM_ANY_OWNER)
|
||||||
|
uid = realuid;
|
||||||
|
if (gid == SMBM_ANY_GROUP)
|
||||||
|
gid = cred->cr_groups[0];
|
||||||
|
vcp->vc_uid = uid;
|
||||||
|
vcp->vc_grp = gid;
|
||||||
|
|
||||||
|
smb_sl_init(&vcp->vc_stlock, "vcstlock");
|
||||||
|
error = 0;
|
||||||
|
itry {
|
||||||
|
vcp->vc_paddr = dup_sockaddr(vcspec->sap, 1);
|
||||||
|
ierror(vcp->vc_paddr == NULL, ENOMEM);
|
||||||
|
|
||||||
|
vcp->vc_laddr = dup_sockaddr(vcspec->lap, 1);
|
||||||
|
ierror(vcp->vc_laddr == NULL, ENOMEM);
|
||||||
|
|
||||||
|
ierror((vcp->vc_pass = smb_strdup(vcspec->pass)) == NULL, ENOMEM);
|
||||||
|
|
||||||
|
vcp->vc_domain = smb_strdup((domain && domain[0]) ? domain : "NODOMAIN");
|
||||||
|
ierror(vcp->vc_domain == NULL, ENOMEM);
|
||||||
|
|
||||||
|
ierror((vcp->vc_srvname = smb_strdup(vcspec->srvname)) == NULL, ENOMEM);
|
||||||
|
ierror((vcp->vc_username = smb_strdup(vcspec->username)) == NULL, ENOMEM);
|
||||||
|
|
||||||
|
ithrow(iconv_open("tolower", vcspec->localcs, &vcp->vc_tolower));
|
||||||
|
ithrow(iconv_open("toupper", vcspec->localcs, &vcp->vc_toupper));
|
||||||
|
if (vcspec->servercs[0]) {
|
||||||
|
ithrow(iconv_open(vcspec->servercs, vcspec->localcs,
|
||||||
|
&vcp->vc_toserver));
|
||||||
|
ithrow(iconv_open(vcspec->localcs, vcspec->servercs,
|
||||||
|
&vcp->vc_tolocal));
|
||||||
|
}
|
||||||
|
|
||||||
|
ithrow(smb_iod_create(vcp));
|
||||||
|
*vcpp = vcp;
|
||||||
|
smb_co_addchild(&smb_vclist, VCTOCP(vcp));
|
||||||
|
} icatch(error) {
|
||||||
|
smb_vc_put(vcp, scred);
|
||||||
|
} ifinally {
|
||||||
|
} iendtry;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_vc_free(struct smb_connobj *cp)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = CPTOVC(cp);
|
||||||
|
|
||||||
|
if (vcp->vc_iod)
|
||||||
|
smb_iod_destroy(vcp->vc_iod);
|
||||||
|
SMB_STRFREE(vcp->vc_username);
|
||||||
|
SMB_STRFREE(vcp->vc_srvname);
|
||||||
|
SMB_STRFREE(vcp->vc_pass);
|
||||||
|
SMB_STRFREE(vcp->vc_domain);
|
||||||
|
if (vcp->vc_paddr)
|
||||||
|
free(vcp->vc_paddr, M_SONAME);
|
||||||
|
if (vcp->vc_laddr)
|
||||||
|
free(vcp->vc_laddr, M_SONAME);
|
||||||
|
if (vcp->vc_tolower)
|
||||||
|
iconv_close(vcp->vc_tolower);
|
||||||
|
if (vcp->vc_toupper)
|
||||||
|
iconv_close(vcp->vc_toupper);
|
||||||
|
if (vcp->vc_tolocal)
|
||||||
|
iconv_close(vcp->vc_tolocal);
|
||||||
|
if (vcp->vc_toserver)
|
||||||
|
iconv_close(vcp->vc_toserver);
|
||||||
|
smb_co_done(VCTOCP(vcp));
|
||||||
|
smb_sl_destroy(&vcp->vc_stlock);
|
||||||
|
free(vcp, M_SMBCONN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when use count of VC dropped to zero.
|
||||||
|
* VC should be locked on enter with LK_DRAIN.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
smb_vc_gone(struct smb_connobj *cp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = CPTOVC(cp);
|
||||||
|
|
||||||
|
smb_vc_disconnect(vcp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_vc_ref(struct smb_vc *vcp, struct proc *p)
|
||||||
|
{
|
||||||
|
smb_co_ref(VCTOCP(vcp), p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_vc_rele(struct smb_vc *vcp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
smb_co_rele(VCTOCP(vcp), scred);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_vc_get(struct smb_vc *vcp, int flags, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
return smb_co_get(VCTOCP(vcp), flags, scred);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_vc_put(struct smb_vc *vcp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
smb_co_put(VCTOCP(vcp), scred);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_vc_lock(struct smb_vc *vcp, int flags, struct proc *p)
|
||||||
|
{
|
||||||
|
return smb_co_lock(VCTOCP(vcp), flags, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_vc_unlock(struct smb_vc *vcp, int flags, struct proc *p)
|
||||||
|
{
|
||||||
|
smb_co_unlock(VCTOCP(vcp), flags, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_vc_access(struct smb_vc *vcp, struct smb_cred *scred, mode_t mode)
|
||||||
|
{
|
||||||
|
struct ucred *cred = scred->scr_cred;
|
||||||
|
|
||||||
|
if (smb_suser(cred) == 0 || cred->cr_uid == vcp->vc_uid)
|
||||||
|
return 0;
|
||||||
|
mode >>= 3;
|
||||||
|
if (!groupmember(vcp->vc_grp, cred))
|
||||||
|
mode >>= 3;
|
||||||
|
return (vcp->vc_mode & mode) == mode ? 0 : EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_vc_cmpshare(struct smb_share *ssp, struct smb_sharespec *dp)
|
||||||
|
{
|
||||||
|
int exact = 1;
|
||||||
|
|
||||||
|
if (strcmp(ssp->ss_name, dp->name) != 0)
|
||||||
|
return 1;
|
||||||
|
if (dp->owner != SMBM_ANY_OWNER) {
|
||||||
|
if (ssp->ss_uid != dp->owner)
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
exact = 0;
|
||||||
|
if (dp->group != SMBM_ANY_GROUP) {
|
||||||
|
if (ssp->ss_grp != dp->group)
|
||||||
|
return 1;
|
||||||
|
} else
|
||||||
|
exact = 0;
|
||||||
|
|
||||||
|
if (dp->mode & SMBM_EXACT) {
|
||||||
|
if (!exact)
|
||||||
|
return 1;
|
||||||
|
return (dp->mode & SMBM_MASK) == ssp->ss_mode ? 0 : 1;
|
||||||
|
}
|
||||||
|
if (smb_share_access(ssp, dp->scred, dp->mode) != 0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup share in the given VC. Share referenced and locked on return.
|
||||||
|
* VC expected to be locked on entry and will be left locked on exit.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *dp,
|
||||||
|
struct smb_cred *scred, struct smb_share **sspp)
|
||||||
|
{
|
||||||
|
struct proc *p = scred->scr_p;
|
||||||
|
struct smb_share *ssp = NULL;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
*sspp = NULL;
|
||||||
|
dp->scred = scred;
|
||||||
|
SMBCO_FOREACH((struct smb_connobj*)ssp, VCTOCP(vcp)) {
|
||||||
|
error = smb_share_lock(ssp, LK_EXCLUSIVE, p);
|
||||||
|
if (error)
|
||||||
|
continue;
|
||||||
|
if (smb_vc_cmpshare(ssp, dp) == 0)
|
||||||
|
break;
|
||||||
|
smb_share_unlock(ssp, 0, p);
|
||||||
|
}
|
||||||
|
if (ssp) {
|
||||||
|
smb_share_ref(ssp, p);
|
||||||
|
*sspp = ssp;
|
||||||
|
error = 0;
|
||||||
|
} else
|
||||||
|
error = ENOENT;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_vc_connect(struct smb_vc *vcp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
|
||||||
|
return smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Destroy VC to server, invalidate shares linked with it.
|
||||||
|
* Transport should be locked on entry.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smb_vc_disconnect(struct smb_vc *vcp)
|
||||||
|
{
|
||||||
|
|
||||||
|
smb_iod_request(vcp->vc_iod, SMBIOD_EV_DISCONNECT | SMBIOD_EV_SYNC, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char smb_emptypass[] = "";
|
||||||
|
|
||||||
|
const char *
|
||||||
|
smb_vc_getpass(struct smb_vc *vcp)
|
||||||
|
{
|
||||||
|
if (vcp->vc_pass)
|
||||||
|
return vcp->vc_pass;
|
||||||
|
return smb_emptypass;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_vc_getinfo(struct smb_vc *vcp, struct smb_vc_info *vip)
|
||||||
|
{
|
||||||
|
bzero(vip, sizeof(struct smb_vc_info));
|
||||||
|
vip->itype = SMB_INFO_VC;
|
||||||
|
vip->usecount = vcp->obj.co_usecount;
|
||||||
|
vip->uid = vcp->vc_uid;
|
||||||
|
vip->gid = vcp->vc_grp;
|
||||||
|
vip->mode = vcp->vc_mode;
|
||||||
|
vip->flags = vcp->obj.co_flags;
|
||||||
|
vip->sopt = vcp->vc_sopt;
|
||||||
|
vip->iodstate = vcp->vc_iod->iod_state;
|
||||||
|
bzero(&vip->sopt.sv_skey, sizeof(vip->sopt.sv_skey));
|
||||||
|
snprintf(vip->srvname, sizeof(vip->srvname), "%s", vcp->vc_srvname);
|
||||||
|
snprintf(vip->vcname, sizeof(vip->vcname), "%s", vcp->vc_username);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_short
|
||||||
|
smb_vc_nextmid(struct smb_vc *vcp)
|
||||||
|
{
|
||||||
|
u_short r;
|
||||||
|
|
||||||
|
SMB_CO_LOCK(&vcp->obj);
|
||||||
|
r = vcp->vc_mid++;
|
||||||
|
SMB_CO_UNLOCK(&vcp->obj);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Share implementation
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Allocate share structure and attach it to the given VC
|
||||||
|
* Connection expected to be locked on entry. Share will be returned
|
||||||
|
* in locked state.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec,
|
||||||
|
struct smb_cred *scred, struct smb_share **sspp)
|
||||||
|
{
|
||||||
|
struct smb_share *ssp;
|
||||||
|
struct proc *p = scred->scr_p;
|
||||||
|
struct ucred *cred = scred->scr_cred;
|
||||||
|
uid_t realuid = cred->cr_uid;
|
||||||
|
uid_t uid = shspec->owner;
|
||||||
|
gid_t gid = shspec->group;
|
||||||
|
int error, isroot;
|
||||||
|
|
||||||
|
isroot = smb_suser(cred) == 0;
|
||||||
|
/*
|
||||||
|
* Only superuser can create shares with different uid and gid
|
||||||
|
*/
|
||||||
|
if (uid != SMBM_ANY_OWNER && uid != realuid && !isroot)
|
||||||
|
return EPERM;
|
||||||
|
if (gid != SMBM_ANY_GROUP && !groupmember(gid, cred) && !isroot)
|
||||||
|
return EPERM;
|
||||||
|
error = smb_vc_lookupshare(vcp, shspec, scred, &ssp);
|
||||||
|
if (!error) {
|
||||||
|
smb_share_put(ssp, scred);
|
||||||
|
return EEXIST;
|
||||||
|
}
|
||||||
|
if (uid == SMBM_ANY_OWNER)
|
||||||
|
uid = realuid;
|
||||||
|
if (gid == SMBM_ANY_GROUP)
|
||||||
|
gid = cred->cr_groups[0];
|
||||||
|
ssp = smb_zmalloc(sizeof(*ssp), M_SMBCONN, M_WAITOK);
|
||||||
|
smb_co_init(SSTOCP(ssp), SMBL_SHARE, "smbss", p);
|
||||||
|
ssp->obj.co_free = smb_share_free;
|
||||||
|
ssp->obj.co_gone = smb_share_gone;
|
||||||
|
smb_sl_init(&ssp->ss_stlock, "ssstlock");
|
||||||
|
ssp->ss_name = smb_strdup(shspec->name);
|
||||||
|
if (shspec->pass && shspec->pass[0])
|
||||||
|
ssp->ss_pass = smb_strdup(shspec->pass);
|
||||||
|
ssp->ss_type = shspec->stype;
|
||||||
|
ssp->ss_tid = SMB_TID_UNKNOWN;
|
||||||
|
ssp->ss_uid = uid;
|
||||||
|
ssp->ss_grp = gid;
|
||||||
|
ssp->ss_mode = shspec->rights & SMBM_MASK;
|
||||||
|
smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));
|
||||||
|
*sspp = ssp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_share_free(struct smb_connobj *cp)
|
||||||
|
{
|
||||||
|
struct smb_share *ssp = CPTOSS(cp);
|
||||||
|
|
||||||
|
SMB_STRFREE(ssp->ss_name);
|
||||||
|
SMB_STRFREE(ssp->ss_pass);
|
||||||
|
smb_sl_destroy(&ssp->ss_stlock);
|
||||||
|
smb_co_done(SSTOCP(ssp));
|
||||||
|
free(ssp, M_SMBCONN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_share_gone(struct smb_connobj *cp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_share *ssp = CPTOSS(cp);
|
||||||
|
|
||||||
|
smb_smb_treedisconnect(ssp, scred);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_share_ref(struct smb_share *ssp, struct proc *p)
|
||||||
|
{
|
||||||
|
smb_co_ref(SSTOCP(ssp), p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_share_rele(struct smb_share *ssp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
smb_co_rele(SSTOCP(ssp), scred);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_share_get(struct smb_share *ssp, int flags, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
return smb_co_get(SSTOCP(ssp), flags, scred);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_share_put(struct smb_share *ssp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
smb_co_put(SSTOCP(ssp), scred);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_share_lock(struct smb_share *ssp, int flags, struct proc *p)
|
||||||
|
{
|
||||||
|
return smb_co_lock(SSTOCP(ssp), flags, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_share_unlock(struct smb_share *ssp, int flags, struct proc *p)
|
||||||
|
{
|
||||||
|
smb_co_unlock(SSTOCP(ssp), flags, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_share_access(struct smb_share *ssp, struct smb_cred *scred, mode_t mode)
|
||||||
|
{
|
||||||
|
struct ucred *cred = scred->scr_cred;
|
||||||
|
|
||||||
|
if (smb_suser(cred) == 0 || cred->cr_uid == ssp->ss_uid)
|
||||||
|
return 0;
|
||||||
|
mode >>= 3;
|
||||||
|
if (!groupmember(ssp->ss_grp, cred))
|
||||||
|
mode >>= 3;
|
||||||
|
return (ssp->ss_mode & mode) == mode ? 0 : EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_share_invalidate(struct smb_share *ssp)
|
||||||
|
{
|
||||||
|
ssp->ss_tid = SMB_TID_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_share_valid(struct smb_share *ssp)
|
||||||
|
{
|
||||||
|
return ssp->ss_tid != SMB_TID_UNKNOWN &&
|
||||||
|
ssp->ss_vcgenid == SSTOVC(ssp)->vc_genid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
smb_share_getpass(struct smb_share *ssp)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp;
|
||||||
|
|
||||||
|
if (ssp->ss_pass)
|
||||||
|
return ssp->ss_pass;
|
||||||
|
vcp = SSTOVC(ssp);
|
||||||
|
if (vcp->vc_pass)
|
||||||
|
return vcp->vc_pass;
|
||||||
|
return smb_emptypass;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_share_getinfo(struct smb_share *ssp, struct smb_share_info *sip)
|
||||||
|
{
|
||||||
|
bzero(sip, sizeof(struct smb_share_info));
|
||||||
|
sip->itype = SMB_INFO_SHARE;
|
||||||
|
sip->usecount = ssp->obj.co_usecount;
|
||||||
|
sip->tid = ssp->ss_tid;
|
||||||
|
sip->type= ssp->ss_type;
|
||||||
|
sip->uid = ssp->ss_uid;
|
||||||
|
sip->gid = ssp->ss_grp;
|
||||||
|
sip->mode= ssp->ss_mode;
|
||||||
|
sip->flags = ssp->obj.co_flags;
|
||||||
|
snprintf(sip->sname, sizeof(sip->sname), "%s", ssp->ss_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump an entire tree into sysctl call
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
smb_sysctl_treedump(SYSCTL_HANDLER_ARGS)
|
||||||
|
{
|
||||||
|
struct proc *p = req->p;
|
||||||
|
struct smb_cred scred;
|
||||||
|
struct smb_vc *vcp;
|
||||||
|
struct smb_share *ssp;
|
||||||
|
struct smb_vc_info vci;
|
||||||
|
struct smb_share_info ssi;
|
||||||
|
int error, itype;
|
||||||
|
|
||||||
|
smb_makescred(&scred, p, p->p_ucred);
|
||||||
|
error = smb_sm_lockvclist(LK_SHARED, p);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
SMBCO_FOREACH((struct smb_connobj*)vcp, &smb_vclist) {
|
||||||
|
error = smb_vc_lock(vcp, LK_SHARED, p);
|
||||||
|
if (error)
|
||||||
|
continue;
|
||||||
|
smb_vc_getinfo(vcp, &vci);
|
||||||
|
error = SYSCTL_OUT(req, &vci, sizeof(struct smb_vc_info));
|
||||||
|
if (error) {
|
||||||
|
smb_vc_unlock(vcp, 0, p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SMBCO_FOREACH((struct smb_connobj*)ssp, VCTOCP(vcp)) {
|
||||||
|
error = smb_share_lock(ssp, LK_SHARED, p);
|
||||||
|
if (error) {
|
||||||
|
error = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
smb_share_getinfo(ssp, &ssi);
|
||||||
|
smb_share_unlock(ssp, 0, p);
|
||||||
|
error = SYSCTL_OUT(req, &ssi, sizeof(struct smb_share_info));
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
smb_vc_unlock(vcp, 0, p);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!error) {
|
||||||
|
itype = SMB_INFO_NONE;
|
||||||
|
error = SYSCTL_OUT(req, &itype, sizeof(itype));
|
||||||
|
}
|
||||||
|
smb_sm_unlockvclist(p);
|
||||||
|
return error;
|
||||||
|
}
|
464
sys/netsmb/smb_conn.h
Normal file
464
sys/netsmb/smb_conn.h
Normal file
@ -0,0 +1,464 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001 Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#ifndef _NETINET_IN_H_
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Two levels of connection hierarchy
|
||||||
|
*/
|
||||||
|
#define SMBL_SM 0
|
||||||
|
#define SMBL_VC 1
|
||||||
|
#define SMBL_SHARE 2
|
||||||
|
#define SMBL_NUM 3
|
||||||
|
#define SMBL_NONE (-1)
|
||||||
|
|
||||||
|
#define SMB_CS_NONE 0x0000
|
||||||
|
#define SMB_CS_UPPER 0x0001 /* convert passed string to upper case */
|
||||||
|
#define SMB_CS_LOWER 0x0002 /* convert passed string to lower case */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common object flags
|
||||||
|
*/
|
||||||
|
#define SMBO_GONE 0x1000000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* access modes
|
||||||
|
*/
|
||||||
|
#define SMBM_READ 0400 /* read conn attrs.(like list shares) */
|
||||||
|
#define SMBM_WRITE 0200 /* modify conn attrs */
|
||||||
|
#define SMBM_EXEC 0100 /* can send SMB requests */
|
||||||
|
#define SMBM_READGRP 0040
|
||||||
|
#define SMBM_WRITEGRP 0020
|
||||||
|
#define SMBM_EXECGRP 0010
|
||||||
|
#define SMBM_READOTH 0004
|
||||||
|
#define SMBM_WRITEOTH 0002
|
||||||
|
#define SMBM_EXECOTH 0001
|
||||||
|
#define SMBM_MASK 0777
|
||||||
|
#define SMBM_EXACT 010000 /* check for specified mode exactly */
|
||||||
|
#define SMBM_ALL (SMBM_READ | SMBM_WRITE | SMBM_EXEC)
|
||||||
|
#define SMBM_DEFAULT (SMBM_READ | SMBM_WRITE | SMBM_EXEC)
|
||||||
|
#define SMBM_ANY_OWNER ((uid_t)-1)
|
||||||
|
#define SMBM_ANY_GROUP ((gid_t)-1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VC flags
|
||||||
|
*/
|
||||||
|
#define SMBV_PERMANENT 0x0002
|
||||||
|
#define SMBV_LONGNAMES 0x0004 /* connection is configured to use long names */
|
||||||
|
#define SMBV_ENCRYPT 0x0008 /* server asked for encrypted password */
|
||||||
|
#define SMBV_WIN95 0x0010 /* used to apply bugfixes for this OS */
|
||||||
|
#define SMBV_PRIVATE 0x0020 /* connection can be used only by creator */
|
||||||
|
#define SMBV_RECONNECTING 0x0040 /* conn is in the process of reconnection */
|
||||||
|
#define SMBV_SINGLESHARE 0x0080 /* only one share connectin should be allowed */
|
||||||
|
#define SMBV_CREATE 0x0100 /* lookup for create opeartion */
|
||||||
|
/*#define SMBV_FAILED 0x0200*/ /* last reconnect attempt has failed */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* smb_share flags
|
||||||
|
*/
|
||||||
|
#define SMBS_PERMANENT 0x0001
|
||||||
|
#define SMBS_RECONNECTING 0x0002
|
||||||
|
#define SMBS_CONNECTED 0x0004
|
||||||
|
|
||||||
|
/*
|
||||||
|
* share types
|
||||||
|
*/
|
||||||
|
#define SMB_ST_DISK 0x0 /* A: */
|
||||||
|
#define SMB_ST_PRINTER 0x1 /* LPT: */
|
||||||
|
#define SMB_ST_PIPE 0x2 /* IPC */
|
||||||
|
#define SMB_ST_COMM 0x3 /* COMM */
|
||||||
|
#define SMB_ST_ANY 0x4
|
||||||
|
#define SMB_ST_MAX 0x4
|
||||||
|
#define SMB_ST_NONE 0xff /* not a part of protocol */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Negotiated protocol parameters
|
||||||
|
*/
|
||||||
|
struct smb_sopt {
|
||||||
|
int sv_proto;
|
||||||
|
int16_t sv_tz; /* offset in min relative to UTC */
|
||||||
|
u_int32_t sv_maxtx; /* maximum transmit buf size */
|
||||||
|
u_char sv_sm; /* security mode */
|
||||||
|
u_int16_t sv_maxmux; /* max number of outstanding rq's */
|
||||||
|
u_int16_t sv_maxvcs; /* max number of VCs */
|
||||||
|
u_int16_t sv_rawmode;
|
||||||
|
u_int32_t sv_maxraw; /* maximum raw-buffer size */
|
||||||
|
u_int32_t sv_skey; /* session key */
|
||||||
|
u_int32_t sv_caps; /* capabilites SMB_CAP_ */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* network IO daemon states
|
||||||
|
*/
|
||||||
|
enum smbiod_state {
|
||||||
|
SMBIOD_ST_NOTCONN, /* no connect request was made */
|
||||||
|
SMBIOD_ST_RECONNECT, /* a [re]connect attempt is in progress */
|
||||||
|
SMBIOD_ST_TRANACTIVE, /* transport level is up */
|
||||||
|
SMBIOD_ST_VCACTIVE, /* session established */
|
||||||
|
SMBIOD_ST_DEAD /* connection broken, transport is down */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Info structures
|
||||||
|
*/
|
||||||
|
#define SMB_INFO_NONE 0
|
||||||
|
#define SMB_INFO_VC 2
|
||||||
|
#define SMB_INFO_SHARE 3
|
||||||
|
|
||||||
|
struct smb_vc_info {
|
||||||
|
int itype;
|
||||||
|
int usecount;
|
||||||
|
uid_t uid; /* user id of connection */
|
||||||
|
gid_t gid; /* group of connection */
|
||||||
|
mode_t mode; /* access mode */
|
||||||
|
int flags;
|
||||||
|
enum smbiod_state iodstate;
|
||||||
|
struct smb_sopt sopt;
|
||||||
|
char srvname[SMB_MAXSRVNAMELEN];
|
||||||
|
char vcname[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smb_share_info {
|
||||||
|
int itype;
|
||||||
|
int usecount;
|
||||||
|
u_short tid; /* TID */
|
||||||
|
int type; /* share type */
|
||||||
|
uid_t uid; /* user id of connection */
|
||||||
|
gid_t gid; /* group of connection */
|
||||||
|
mode_t mode; /* access mode */
|
||||||
|
int flags;
|
||||||
|
char sname[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
|
||||||
|
#define CONNADDREQ(a1,a2) ((a1)->sa_len == (a2)->sa_len && \
|
||||||
|
bcmp(a1, a2, (a1)->sa_len) == 0)
|
||||||
|
|
||||||
|
struct smb_vc;
|
||||||
|
struct smb_share;
|
||||||
|
struct smb_cred;
|
||||||
|
struct smb_rq;
|
||||||
|
struct mbdata;
|
||||||
|
struct smbioc_oshare;
|
||||||
|
struct smbioc_ossn;
|
||||||
|
struct uio;
|
||||||
|
|
||||||
|
TAILQ_HEAD(smb_rqhead, smb_rq);
|
||||||
|
|
||||||
|
#define SMB_DEFRQTIMO 5
|
||||||
|
|
||||||
|
#define SMB_DIALECT(vcp) ((vcp)->vc_sopt.sv_proto)
|
||||||
|
|
||||||
|
struct smb_tran_desc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Connection object
|
||||||
|
*/
|
||||||
|
struct smb_connobj;
|
||||||
|
|
||||||
|
typedef void smb_co_gone_t (struct smb_connobj *cp, struct smb_cred *scred);
|
||||||
|
typedef void smb_co_free_t (struct smb_connobj *cp);
|
||||||
|
|
||||||
|
#define SMB_CO_LOCK(cp) smb_sl_lock(&(cp)->co_interlock)
|
||||||
|
#define SMB_CO_UNLOCK(cp) smb_sl_unlock(&(cp)->co_interlock)
|
||||||
|
|
||||||
|
struct smb_connobj {
|
||||||
|
int co_level; /* SMBL_ */
|
||||||
|
int co_flags;
|
||||||
|
struct lock co_lock;
|
||||||
|
struct smb_slock co_interlock;
|
||||||
|
int co_usecount;
|
||||||
|
struct smb_connobj * co_parent;
|
||||||
|
SLIST_HEAD(,smb_connobj)co_children;
|
||||||
|
SLIST_ENTRY(smb_connobj)co_next;
|
||||||
|
smb_co_gone_t * co_gone;
|
||||||
|
smb_co_free_t * co_free;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SMBCO_FOREACH(var, cp) SLIST_FOREACH((var), &(cp)->co_children, co_next)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Virtual Circuit (session) to a server.
|
||||||
|
* This is the most (over)complicated part of SMB protocol.
|
||||||
|
* For the user security level (usl), each session with different remote
|
||||||
|
* user name has its own VC.
|
||||||
|
* It is unclear however, should share security level (ssl) allow additional
|
||||||
|
* VCs, because user name is not used and can be the same. On other hand,
|
||||||
|
* multiple VCs allows us to create separate sessions to server on a per
|
||||||
|
* user basis.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This lock protects vc_flags
|
||||||
|
*/
|
||||||
|
#define SMBC_ST_LOCK(vcp) smb_sl_lock(&(vcp)->vc_stlock)
|
||||||
|
#define SMBC_ST_UNLOCK(vcp) smb_sl_unlock(&(vcp)->vc_stlock)
|
||||||
|
|
||||||
|
|
||||||
|
struct smb_vc {
|
||||||
|
struct smb_connobj obj;
|
||||||
|
char * vc_srvname;
|
||||||
|
struct sockaddr*vc_paddr; /* server addr */
|
||||||
|
struct sockaddr*vc_laddr; /* local addr, if any */
|
||||||
|
char * vc_username;
|
||||||
|
char * vc_pass; /* password for usl case */
|
||||||
|
char * vc_domain; /* workgroup/primary domain */
|
||||||
|
|
||||||
|
u_int vc_timo; /* default request timeout */
|
||||||
|
int vc_maxvcs; /* maximum number of VC per connection */
|
||||||
|
|
||||||
|
void * vc_tolower; /* local charset */
|
||||||
|
void * vc_toupper; /* local charset */
|
||||||
|
void * vc_toserver; /* local charset to server one */
|
||||||
|
void * vc_tolocal; /* server charset to local one */
|
||||||
|
int vc_number; /* number of this VC from the client side */
|
||||||
|
int vc_genid;
|
||||||
|
uid_t vc_uid; /* user id of connection */
|
||||||
|
gid_t vc_grp; /* group of connection */
|
||||||
|
mode_t vc_mode; /* access mode */
|
||||||
|
struct tnode * vc_tnode; /* backing object */
|
||||||
|
u_short vc_smbuid; /* unique vc id assigned by server */
|
||||||
|
|
||||||
|
u_char vc_hflags; /* or'ed with flags in the smb header */
|
||||||
|
u_short vc_hflags2; /* or'ed with flags in the smb header */
|
||||||
|
void * vc_tdata; /* transport control block */
|
||||||
|
struct smb_tran_desc *vc_tdesc;
|
||||||
|
int vc_chlen; /* actual challenge length */
|
||||||
|
u_char vc_ch[SMB_MAXCHALLENGELEN];
|
||||||
|
u_short vc_mid; /* multiplex id */
|
||||||
|
struct smb_sopt vc_sopt; /* server options */
|
||||||
|
struct smb_cred*vc_scred; /* used in reconnect procedure */
|
||||||
|
int vc_txmax; /* max tx/rx packet size */
|
||||||
|
struct smbiod * vc_iod;
|
||||||
|
struct smb_slock vc_stlock;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define vc_maxmux vc_sopt.sv_maxmux
|
||||||
|
#define vc_flags obj.co_flags
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* smb_share structure describes connection to the given SMB share (tree).
|
||||||
|
* Connection to share is always built on top of the VC.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This lock protects ss_flags
|
||||||
|
*/
|
||||||
|
#define SMBS_ST_LOCK(ssp) smb_sl_lock(&(ssp)->ss_stlock)
|
||||||
|
#define SMBS_ST_LOCKPTR(ssp) (&(ssp)->ss_stlock)
|
||||||
|
#define SMBS_ST_UNLOCK(ssp) smb_sl_unlock(&(ssp)->ss_stlock)
|
||||||
|
|
||||||
|
struct smb_share {
|
||||||
|
struct smb_connobj obj;
|
||||||
|
char * ss_name;
|
||||||
|
u_short ss_tid; /* TID */
|
||||||
|
int ss_type; /* share type */
|
||||||
|
uid_t ss_uid; /* user id of connection */
|
||||||
|
gid_t ss_grp; /* group of connection */
|
||||||
|
mode_t ss_mode; /* access mode */
|
||||||
|
int ss_vcgenid;
|
||||||
|
char * ss_pass; /* password to a share, can be null */
|
||||||
|
struct smb_slock ss_stlock;
|
||||||
|
struct smb_cred *ss_cred; /* used in reconnect procedure */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ss_flags obj.co_flags
|
||||||
|
|
||||||
|
#define CPTOVC(cp) ((struct smb_vc*)(cp))
|
||||||
|
#define VCTOCP(vcp) (&(vcp)->obj)
|
||||||
|
#define CPTOSS(cp) ((struct smb_share*)(cp))
|
||||||
|
#define SSTOVC(ssp) CPTOVC(((ssp)->obj.co_parent))
|
||||||
|
#define SSTOCP(ssp) (&(ssp)->obj)
|
||||||
|
|
||||||
|
struct smb_vcspec {
|
||||||
|
char * srvname;
|
||||||
|
struct sockaddr*sap;
|
||||||
|
struct sockaddr*lap;
|
||||||
|
int flags;
|
||||||
|
char * username;
|
||||||
|
char * pass;
|
||||||
|
char * domain;
|
||||||
|
mode_t mode;
|
||||||
|
mode_t rights;
|
||||||
|
uid_t owner;
|
||||||
|
gid_t group;
|
||||||
|
char * localcs;
|
||||||
|
char * servercs;
|
||||||
|
struct smb_sharespec *shspec;
|
||||||
|
struct smb_share *ssp; /* returned */
|
||||||
|
/*
|
||||||
|
* The rest is an internal data
|
||||||
|
*/
|
||||||
|
struct smb_cred *scred;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smb_sharespec {
|
||||||
|
char * name;
|
||||||
|
char * pass;
|
||||||
|
mode_t mode;
|
||||||
|
mode_t rights;
|
||||||
|
uid_t owner;
|
||||||
|
gid_t group;
|
||||||
|
int stype;
|
||||||
|
/*
|
||||||
|
* The rest is an internal data
|
||||||
|
*/
|
||||||
|
struct smb_cred *scred;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Session level functions
|
||||||
|
*/
|
||||||
|
int smb_sm_init(void);
|
||||||
|
int smb_sm_done(void);
|
||||||
|
int smb_sm_lookup(struct smb_vcspec *vcspec,
|
||||||
|
struct smb_sharespec *shspec, struct smb_cred *scred,
|
||||||
|
struct smb_vc **vcpp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Connection object
|
||||||
|
*/
|
||||||
|
void smb_co_ref(struct smb_connobj *cp, struct proc *p);
|
||||||
|
void smb_co_rele(struct smb_connobj *cp, struct smb_cred *scred);
|
||||||
|
int smb_co_get(struct smb_connobj *cp, int flags, struct smb_cred *scred);
|
||||||
|
void smb_co_put(struct smb_connobj *cp, struct smb_cred *scred);
|
||||||
|
int smb_co_lock(struct smb_connobj *cp, int flags, struct proc *p);
|
||||||
|
void smb_co_unlock(struct smb_connobj *cp, int flags, struct proc *p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* session level functions
|
||||||
|
*/
|
||||||
|
int smb_vc_create(struct smb_vcspec *vcspec,
|
||||||
|
struct smb_cred *scred, struct smb_vc **vcpp);
|
||||||
|
int smb_vc_connect(struct smb_vc *vcp, struct smb_cred *scred);
|
||||||
|
int smb_vc_access(struct smb_vc *vcp, struct smb_cred *scred, mode_t mode);
|
||||||
|
int smb_vc_get(struct smb_vc *vcp, int flags, struct smb_cred *scred);
|
||||||
|
void smb_vc_put(struct smb_vc *vcp, struct smb_cred *scred);
|
||||||
|
void smb_vc_ref(struct smb_vc *vcp, struct proc *p);
|
||||||
|
void smb_vc_rele(struct smb_vc *vcp, struct smb_cred *scred);
|
||||||
|
int smb_vc_lock(struct smb_vc *vcp, int flags, struct proc *p);
|
||||||
|
void smb_vc_unlock(struct smb_vc *vcp, int flags, struct proc *p);
|
||||||
|
int smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *shspec,
|
||||||
|
struct smb_cred *scred, struct smb_share **sspp);
|
||||||
|
const char * smb_vc_getpass(struct smb_vc *vcp);
|
||||||
|
u_short smb_vc_nextmid(struct smb_vc *vcp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* share level functions
|
||||||
|
*/
|
||||||
|
int smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec,
|
||||||
|
struct smb_cred *scred, struct smb_share **sspp);
|
||||||
|
int smb_share_access(struct smb_share *ssp, struct smb_cred *scred, mode_t mode);
|
||||||
|
void smb_share_ref(struct smb_share *ssp, struct proc *p);
|
||||||
|
void smb_share_rele(struct smb_share *ssp, struct smb_cred *scred);
|
||||||
|
int smb_share_get(struct smb_share *ssp, int flags, struct smb_cred *scred);
|
||||||
|
void smb_share_put(struct smb_share *ssp, struct smb_cred *scred);
|
||||||
|
int smb_share_lock(struct smb_share *ssp, int flags, struct proc *p);
|
||||||
|
void smb_share_unlock(struct smb_share *ssp, int flags, struct proc *p);
|
||||||
|
void smb_share_invalidate(struct smb_share *ssp);
|
||||||
|
int smb_share_valid(struct smb_share *ssp);
|
||||||
|
const char * smb_share_getpass(struct smb_share *ssp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SMB protocol level functions
|
||||||
|
*/
|
||||||
|
int smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred);
|
||||||
|
int smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred);
|
||||||
|
int smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred);
|
||||||
|
int smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred);
|
||||||
|
int smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred);
|
||||||
|
int smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
|
||||||
|
struct smb_cred *scred);
|
||||||
|
int smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
|
||||||
|
struct smb_cred *scred);
|
||||||
|
int smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* smbiod thread
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SMBIOD_EV_NEWRQ 0x0001
|
||||||
|
#define SMBIOD_EV_SHUTDOWN 0x0002
|
||||||
|
#define SMBIOD_EV_CONNECT 0x0003
|
||||||
|
#define SMBIOD_EV_DISCONNECT 0x0004
|
||||||
|
#define SMBIOD_EV_TREECONNECT 0x0005
|
||||||
|
#define SMBIOD_EV_MASK 0x00ff
|
||||||
|
#define SMBIOD_EV_SYNC 0x0100
|
||||||
|
#define SMBIOD_EV_PROCESSING 0x0200
|
||||||
|
|
||||||
|
struct smbiod_event {
|
||||||
|
int ev_type;
|
||||||
|
int ev_error;
|
||||||
|
void * ev_ident;
|
||||||
|
STAILQ_ENTRY(smbiod_event) ev_link;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SMBIOD_SHUTDOWN 0x0001
|
||||||
|
|
||||||
|
struct smbiod {
|
||||||
|
int iod_id;
|
||||||
|
int iod_flags;
|
||||||
|
enum smbiod_state iod_state;
|
||||||
|
int iod_muxcnt; /* number of active outstanding requests */
|
||||||
|
int iod_sleeptimo;
|
||||||
|
struct smb_vc * iod_vc;
|
||||||
|
struct smb_slock iod_rqlock; /* iod_rqlist, iod_muxwant */
|
||||||
|
struct smb_rqhead iod_rqlist; /* list of outstanding requests */
|
||||||
|
int iod_muxwant;
|
||||||
|
struct proc * iod_p;
|
||||||
|
struct smb_cred iod_scred;
|
||||||
|
struct smb_slock iod_evlock; /* iod_evlist */
|
||||||
|
STAILQ_HEAD(,smbiod_event) iod_evlist;
|
||||||
|
struct timespec iod_lastrqsent;
|
||||||
|
struct timespec iod_pingtimo;
|
||||||
|
};
|
||||||
|
|
||||||
|
int smb_iod_init(void);
|
||||||
|
int smb_iod_done(void);
|
||||||
|
int smb_iod_create(struct smb_vc *vcp);
|
||||||
|
int smb_iod_destroy(struct smbiod *iod);
|
||||||
|
int smb_iod_request(struct smbiod *iod, int event, void *ident);
|
||||||
|
int smb_iod_addrq(struct smb_rq *rqp);
|
||||||
|
int smb_iod_waitrq(struct smb_rq *rqp);
|
||||||
|
int smb_iod_removerq(struct smb_rq *rqp);
|
||||||
|
|
||||||
|
#endif /* _KERNEL */
|
146
sys/netsmb/smb_crypt.c
Normal file
146
sys/netsmb/smb_crypt.c
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001, Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/socketvar.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
|
#include <sys/md4.h>
|
||||||
|
#include <sys/iconv.h>
|
||||||
|
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
#include <netsmb/smb_dev.h>
|
||||||
|
|
||||||
|
#include "opt_netsmb.h"
|
||||||
|
|
||||||
|
#ifdef NETSMBCRYPTO
|
||||||
|
|
||||||
|
#include <crypto/des/des.h>
|
||||||
|
|
||||||
|
static u_char N8[] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_E(const u_char *key, u_char *data, u_char *dest)
|
||||||
|
{
|
||||||
|
des_key_schedule *ksp;
|
||||||
|
u_char kk[8];
|
||||||
|
|
||||||
|
kk[0] = key[0] & 0xfe;
|
||||||
|
kk[1] = key[0] << 7 | (key[1] >> 1 & 0xfe);
|
||||||
|
kk[2] = key[1] << 6 | (key[2] >> 2 & 0xfe);
|
||||||
|
kk[3] = key[2] << 5 | (key[3] >> 3 & 0xfe);
|
||||||
|
kk[4] = key[3] << 4 | (key[4] >> 4 & 0xfe);
|
||||||
|
kk[5] = key[4] << 3 | (key[5] >> 5 & 0xfe);
|
||||||
|
kk[6] = key[5] << 2 | (key[6] >> 6 & 0xfe);
|
||||||
|
kk[7] = key[6] << 1;
|
||||||
|
ksp = malloc(sizeof(des_key_schedule), M_SMBTEMP, M_WAITOK);
|
||||||
|
des_set_key((C_Block*)kk, *ksp);
|
||||||
|
des_ecb_encrypt((C_Block*)data, (C_Block*)dest, *ksp, 1);
|
||||||
|
free(ksp, M_SMBTEMP);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_encrypt(const u_char *apwd, u_char *C8, u_char *RN)
|
||||||
|
{
|
||||||
|
#ifdef NETSMBCRYPTO
|
||||||
|
u_char *p, *P14, *S21;
|
||||||
|
|
||||||
|
p = malloc(14 + 21, M_SMBTEMP, M_WAITOK);
|
||||||
|
bzero(p, 14 + 21);
|
||||||
|
P14 = p;
|
||||||
|
S21 = p + 14;
|
||||||
|
bcopy(apwd, P14, min(14, strlen(apwd)));
|
||||||
|
/*
|
||||||
|
* S21 = concat(Ex(P14, N8), zeros(5));
|
||||||
|
*/
|
||||||
|
smb_E(P14, N8, S21);
|
||||||
|
smb_E(P14 + 7, N8, S21 + 8);
|
||||||
|
|
||||||
|
smb_E(S21, C8, RN);
|
||||||
|
smb_E(S21 + 7, C8, RN + 8);
|
||||||
|
smb_E(S21 + 14, C8, RN + 16);
|
||||||
|
free(p, M_SMBTEMP);
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
SMBERROR("password encryption is not available\n");
|
||||||
|
bzero(RN, 24);
|
||||||
|
return EAUTH;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_ntencrypt(const u_char *apwd, u_char *C8, u_char *RN)
|
||||||
|
{
|
||||||
|
#ifdef NETSMBCRYPTO
|
||||||
|
u_char S21[21];
|
||||||
|
u_int16_t *unipwd;
|
||||||
|
MD4_CTX *ctxp;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = strlen(apwd);
|
||||||
|
unipwd = malloc(len * sizeof(u_int16_t), M_SMBTEMP, M_WAITOK);
|
||||||
|
/*
|
||||||
|
* S21 = concat(MD4(U(apwd)), zeros(5));
|
||||||
|
*/
|
||||||
|
smb_strtouni(unipwd, apwd);
|
||||||
|
ctxp = malloc(sizeof(MD4_CTX), M_SMBTEMP, M_WAITOK);
|
||||||
|
MD4Init(ctxp);
|
||||||
|
MD4Update(ctxp, (u_char*)unipwd, len * sizeof(u_int16_t));
|
||||||
|
free(unipwd, M_SMBTEMP);
|
||||||
|
bzero(S21, 21);
|
||||||
|
MD4Final(S21, ctxp);
|
||||||
|
free(ctxp, M_SMBTEMP);
|
||||||
|
|
||||||
|
smb_E(S21, C8, RN);
|
||||||
|
smb_E(S21 + 7, C8, RN + 8);
|
||||||
|
smb_E(S21 + 14, C8, RN + 16);
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
SMBERROR("password encryption is not available\n");
|
||||||
|
bzero(RN, 24);
|
||||||
|
return EAUTH;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
448
sys/netsmb/smb_dev.c
Normal file
448
sys/netsmb/smb_dev.c
Normal file
@ -0,0 +1,448 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001 Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/ioccom.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/mbuf.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/socketvar.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/vnode.h>
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
#include <netsmb/smb_dev.h>
|
||||||
|
|
||||||
|
#define SMB_GETDEV(dev) ((struct smb_dev*)(dev)->si_drv1)
|
||||||
|
#define SMB_CHECKMINOR(dev) do { \
|
||||||
|
sdp = SMB_GETDEV(dev); \
|
||||||
|
if (sdp == NULL) return ENXIO; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
static d_open_t nsmb_dev_open;
|
||||||
|
static d_close_t nsmb_dev_close;
|
||||||
|
static d_read_t nsmb_dev_read;
|
||||||
|
static d_write_t nsmb_dev_write;
|
||||||
|
static d_ioctl_t nsmb_dev_ioctl;
|
||||||
|
static d_poll_t nsmb_dev_poll;
|
||||||
|
|
||||||
|
MODULE_DEPEND(netsmb, libiconv, 1, 1, 1);
|
||||||
|
MODULE_VERSION(netsmb, NSMB_VERSION);
|
||||||
|
|
||||||
|
static int smb_version = NSMB_VERSION;
|
||||||
|
|
||||||
|
|
||||||
|
SYSCTL_DECL(_net_smb);
|
||||||
|
SYSCTL_INT(_net_smb, OID_AUTO, version, CTLFLAG_RD, &smb_version, 0, "");
|
||||||
|
|
||||||
|
static MALLOC_DEFINE(M_NSMBDEV, "NETSMBDEV", "NET/SMB device");
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
int smb_dev_queue(struct smb_dev *ndp, struct smb_rq *rqp, int prio);
|
||||||
|
*/
|
||||||
|
|
||||||
|
static struct cdevsw nsmb_cdevsw = {
|
||||||
|
/* open */ nsmb_dev_open,
|
||||||
|
/* close */ nsmb_dev_close,
|
||||||
|
/* read */ nsmb_dev_read,
|
||||||
|
/* write */ nsmb_dev_write,
|
||||||
|
/* ioctl */ nsmb_dev_ioctl,
|
||||||
|
/* poll */ nsmb_dev_poll,
|
||||||
|
/* mmap */ nommap,
|
||||||
|
/* strategy */ nostrategy,
|
||||||
|
/* name */ NSMB_NAME,
|
||||||
|
/* maj */ NSMB_MAJOR,
|
||||||
|
/* dump */ nodump,
|
||||||
|
/* psize */ nopsize,
|
||||||
|
/* flags */ 0,
|
||||||
|
#ifndef FB_CURRENT
|
||||||
|
/* bmaj */ -1
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static eventhandler_tag nsmb_dev_tag;
|
||||||
|
|
||||||
|
static void
|
||||||
|
nsmb_dev_clone(void *arg, char *name, int namelen, dev_t *dev)
|
||||||
|
{
|
||||||
|
int min;
|
||||||
|
|
||||||
|
if (*dev != NODEV)
|
||||||
|
return;
|
||||||
|
if (dev_stdclone(name, NULL, NSMB_NAME, &min) != 1)
|
||||||
|
return;
|
||||||
|
*dev = make_dev(&nsmb_cdevsw, min, 0, 0, 0600, NSMB_NAME"%d", min);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nsmb_dev_open(dev_t dev, int oflags, int devtype, struct proc *p)
|
||||||
|
{
|
||||||
|
struct smb_dev *sdp;
|
||||||
|
struct ucred *cred = p->p_ucred;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
sdp = SMB_GETDEV(dev);
|
||||||
|
if (sdp && (sdp->sd_flags & NSMBFL_OPEN))
|
||||||
|
return EBUSY;
|
||||||
|
if (sdp == NULL) {
|
||||||
|
sdp = malloc(sizeof(*sdp), M_NSMBDEV, M_WAITOK);
|
||||||
|
dev->si_drv1 = (void*)sdp;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* XXX: this is just crazy - make a device for an already passed device...
|
||||||
|
* someone should take care of it.
|
||||||
|
*/
|
||||||
|
if ((dev->si_flags & SI_NAMED) == 0)
|
||||||
|
make_dev(&nsmb_cdevsw, minor(dev), cred->cr_uid, cred->cr_gid, 0700,
|
||||||
|
NSMB_NAME"%d", dev2unit(dev));
|
||||||
|
bzero(sdp, sizeof(*sdp));
|
||||||
|
/*
|
||||||
|
STAILQ_INIT(&sdp->sd_rqlist);
|
||||||
|
STAILQ_INIT(&sdp->sd_rplist);
|
||||||
|
bzero(&sdp->sd_pollinfo, sizeof(struct selinfo));
|
||||||
|
*/
|
||||||
|
s = splimp();
|
||||||
|
sdp->sd_level = -1;
|
||||||
|
sdp->sd_flags |= NSMBFL_OPEN;
|
||||||
|
splx(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nsmb_dev_close(dev_t dev, int flag, int fmt, struct proc *p)
|
||||||
|
{
|
||||||
|
struct smb_dev *sdp;
|
||||||
|
struct smb_vc *vcp;
|
||||||
|
struct smb_share *ssp;
|
||||||
|
struct smb_cred scred;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
SMB_CHECKMINOR(dev);
|
||||||
|
s = splimp();
|
||||||
|
if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
|
||||||
|
splx(s);
|
||||||
|
return EBADF;
|
||||||
|
}
|
||||||
|
smb_makescred(&scred, p, NULL);
|
||||||
|
ssp = sdp->sd_share;
|
||||||
|
if (ssp != NULL)
|
||||||
|
smb_share_rele(ssp, &scred);
|
||||||
|
vcp = sdp->sd_vc;
|
||||||
|
if (vcp != NULL)
|
||||||
|
smb_vc_rele(vcp, &scred);
|
||||||
|
/*
|
||||||
|
smb_flushq(&sdp->sd_rqlist);
|
||||||
|
smb_flushq(&sdp->sd_rplist);
|
||||||
|
*/
|
||||||
|
#if __FreeBSD_version > 400001
|
||||||
|
dev->si_drv1 = NULL;
|
||||||
|
free(sdp, M_NSMBDEV);
|
||||||
|
destroy_dev(dev);
|
||||||
|
#else
|
||||||
|
sdp->sd_flags &= ~NSMBFL_OPEN;
|
||||||
|
#endif
|
||||||
|
splx(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
nsmb_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
|
||||||
|
{
|
||||||
|
struct smb_dev *sdp;
|
||||||
|
struct smb_vc *vcp;
|
||||||
|
struct smb_share *ssp;
|
||||||
|
struct smb_cred scred;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
SMB_CHECKMINOR(dev);
|
||||||
|
if ((sdp->sd_flags & NSMBFL_OPEN) == 0)
|
||||||
|
return EBADF;
|
||||||
|
|
||||||
|
smb_makescred(&scred, p, NULL);
|
||||||
|
switch (cmd) {
|
||||||
|
case SMBIOC_OPENSESSION:
|
||||||
|
if (sdp->sd_vc)
|
||||||
|
return EISCONN;
|
||||||
|
error = smb_usr_opensession((struct smbioc_ossn*)data,
|
||||||
|
&scred, &vcp);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
sdp->sd_vc = vcp;
|
||||||
|
smb_vc_unlock(vcp, 0, p);
|
||||||
|
sdp->sd_level = SMBL_VC;
|
||||||
|
break;
|
||||||
|
case SMBIOC_OPENSHARE:
|
||||||
|
if (sdp->sd_share)
|
||||||
|
return EISCONN;
|
||||||
|
if (sdp->sd_vc == NULL)
|
||||||
|
return ENOTCONN;
|
||||||
|
error = smb_usr_openshare(sdp->sd_vc,
|
||||||
|
(struct smbioc_oshare*)data, &scred, &ssp);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
sdp->sd_share = ssp;
|
||||||
|
smb_share_unlock(ssp, 0, p);
|
||||||
|
sdp->sd_level = SMBL_SHARE;
|
||||||
|
break;
|
||||||
|
case SMBIOC_REQUEST:
|
||||||
|
if (sdp->sd_share == NULL)
|
||||||
|
return ENOTCONN;
|
||||||
|
error = smb_usr_simplerequest(sdp->sd_share,
|
||||||
|
(struct smbioc_rq*)data, &scred);
|
||||||
|
break;
|
||||||
|
case SMBIOC_T2RQ:
|
||||||
|
if (sdp->sd_share == NULL)
|
||||||
|
return ENOTCONN;
|
||||||
|
error = smb_usr_t2request(sdp->sd_share,
|
||||||
|
(struct smbioc_t2rq*)data, &scred);
|
||||||
|
break;
|
||||||
|
case SMBIOC_SETFLAGS: {
|
||||||
|
struct smbioc_flags *fl = (struct smbioc_flags*)data;
|
||||||
|
int on;
|
||||||
|
|
||||||
|
if (fl->ioc_level == SMBL_VC) {
|
||||||
|
if (fl->ioc_mask & SMBV_PERMANENT) {
|
||||||
|
on = fl->ioc_flags & SMBV_PERMANENT;
|
||||||
|
if ((vcp = sdp->sd_vc) == NULL)
|
||||||
|
return ENOTCONN;
|
||||||
|
error = smb_vc_get(vcp, LK_EXCLUSIVE, &scred);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
if (on && (vcp->obj.co_flags & SMBV_PERMANENT) == 0) {
|
||||||
|
vcp->obj.co_flags |= SMBV_PERMANENT;
|
||||||
|
smb_vc_ref(vcp, p);
|
||||||
|
} else if (!on && (vcp->obj.co_flags & SMBV_PERMANENT)) {
|
||||||
|
vcp->obj.co_flags &= ~SMBV_PERMANENT;
|
||||||
|
smb_vc_rele(vcp, &scred);
|
||||||
|
}
|
||||||
|
smb_vc_put(vcp, &scred);
|
||||||
|
} else
|
||||||
|
error = EINVAL;
|
||||||
|
} else if (fl->ioc_level == SMBL_SHARE) {
|
||||||
|
if (fl->ioc_mask & SMBS_PERMANENT) {
|
||||||
|
on = fl->ioc_flags & SMBS_PERMANENT;
|
||||||
|
if ((ssp = sdp->sd_share) == NULL)
|
||||||
|
return ENOTCONN;
|
||||||
|
error = smb_share_get(ssp, LK_EXCLUSIVE, &scred);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
if (on && (ssp->obj.co_flags & SMBS_PERMANENT) == 0) {
|
||||||
|
ssp->obj.co_flags |= SMBS_PERMANENT;
|
||||||
|
smb_share_ref(ssp, p);
|
||||||
|
} else if (!on && (ssp->obj.co_flags & SMBS_PERMANENT)) {
|
||||||
|
ssp->obj.co_flags &= ~SMBS_PERMANENT;
|
||||||
|
smb_share_rele(ssp, &scred);
|
||||||
|
}
|
||||||
|
smb_share_put(ssp, &scred);
|
||||||
|
} else
|
||||||
|
error = EINVAL;
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
error = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SMBIOC_LOOKUP:
|
||||||
|
if (sdp->sd_vc || sdp->sd_share)
|
||||||
|
return EISCONN;
|
||||||
|
vcp = NULL;
|
||||||
|
ssp = NULL;
|
||||||
|
error = smb_usr_lookup((struct smbioc_lookup*)data, &scred, &vcp, &ssp);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
if (vcp) {
|
||||||
|
sdp->sd_vc = vcp;
|
||||||
|
smb_vc_unlock(vcp, 0, p);
|
||||||
|
sdp->sd_level = SMBL_VC;
|
||||||
|
}
|
||||||
|
if (ssp) {
|
||||||
|
sdp->sd_share = ssp;
|
||||||
|
smb_share_unlock(ssp, 0, p);
|
||||||
|
sdp->sd_level = SMBL_SHARE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SMBIOC_READ: case SMBIOC_WRITE: {
|
||||||
|
struct smbioc_rw *rwrq = (struct smbioc_rw*)data;
|
||||||
|
struct uio auio;
|
||||||
|
struct iovec iov;
|
||||||
|
|
||||||
|
if ((ssp = sdp->sd_share) == NULL)
|
||||||
|
return ENOTCONN;
|
||||||
|
iov.iov_base = rwrq->ioc_base;
|
||||||
|
iov.iov_len = rwrq->ioc_cnt;
|
||||||
|
auio.uio_iov = &iov;
|
||||||
|
auio.uio_iovcnt = 1;
|
||||||
|
auio.uio_offset = rwrq->ioc_offset;
|
||||||
|
auio.uio_resid = rwrq->ioc_cnt;
|
||||||
|
auio.uio_segflg = UIO_USERSPACE;
|
||||||
|
auio.uio_rw = (cmd == SMBIOC_READ) ? UIO_READ : UIO_WRITE;
|
||||||
|
auio.uio_procp = p;
|
||||||
|
if (cmd == SMBIOC_READ)
|
||||||
|
error = smb_read(ssp, rwrq->ioc_fh, &auio, &scred);
|
||||||
|
else
|
||||||
|
error = smb_write(ssp, rwrq->ioc_fh, &auio, &scred);
|
||||||
|
rwrq->ioc_cnt -= auio.uio_resid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
error = ENODEV;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nsmb_dev_read(dev_t dev, struct uio *uio, int flag)
|
||||||
|
{
|
||||||
|
return EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nsmb_dev_write(dev_t dev, struct uio *uio, int flag)
|
||||||
|
{
|
||||||
|
return EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nsmb_dev_poll(dev_t dev, int events, struct proc *p)
|
||||||
|
{
|
||||||
|
return ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nsmb_dev_load(module_t mod, int cmd, void *arg)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case MOD_LOAD:
|
||||||
|
error = smb_sm_init();
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
error = smb_iod_init();
|
||||||
|
if (error) {
|
||||||
|
smb_sm_done();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#if __FreeBSD_version > 400001
|
||||||
|
cdevsw_add(&nsmb_cdevsw);
|
||||||
|
#endif
|
||||||
|
#if __FreeBSD_version > 500000
|
||||||
|
nsmb_dev_tag = EVENTHANDLER_REGISTER(dev_clone, nsmb_dev_clone, 0, 1000);
|
||||||
|
#endif
|
||||||
|
printf("netsmb_dev: loaded\n");
|
||||||
|
break;
|
||||||
|
case MOD_UNLOAD:
|
||||||
|
smb_iod_done();
|
||||||
|
error = smb_sm_done();
|
||||||
|
error = 0;
|
||||||
|
#if __FreeBSD_version > 500000
|
||||||
|
EVENTHANDLER_DEREGISTER(dev_clone, nsmb_dev_tag);
|
||||||
|
#endif
|
||||||
|
#if __FreeBSD_version > 400001
|
||||||
|
cdevsw_remove(&nsmb_cdevsw);
|
||||||
|
#endif
|
||||||
|
printf("netsmb_dev: unloaded\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __FreeBSD_version > 400000
|
||||||
|
DEV_MODULE (dev_netsmb, nsmb_dev_load, 0);
|
||||||
|
#else
|
||||||
|
CDEV_MODULE(dev_netsmb, NSMB_MAJOR, nsmb_cdevsw, nsmb_dev_load, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert a file descriptor to appropriate smb_share pointer
|
||||||
|
*/
|
||||||
|
static struct file*
|
||||||
|
nsmb_getfp(struct filedesc* fdp, int fd, int flag)
|
||||||
|
{
|
||||||
|
struct file* fp;
|
||||||
|
|
||||||
|
if (((u_int)fd) >= fdp->fd_nfiles ||
|
||||||
|
(fp = fdp->fd_ofiles[fd]) == NULL ||
|
||||||
|
(fp->f_flag & flag) == 0)
|
||||||
|
return (NULL);
|
||||||
|
return (fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_dev2share(int fd, int mode, struct smb_cred *scred,
|
||||||
|
struct smb_share **sspp)
|
||||||
|
{
|
||||||
|
struct file *fp;
|
||||||
|
struct vnode *vp;
|
||||||
|
struct smb_dev *sdp;
|
||||||
|
struct smb_share *ssp;
|
||||||
|
dev_t dev;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if ((fp = nsmb_getfp(scred->scr_p->p_fd, fd, FREAD | FWRITE)) == NULL)
|
||||||
|
return EBADF;
|
||||||
|
vp = (struct vnode*)fp->f_data;
|
||||||
|
if (vp == NULL)
|
||||||
|
return EBADF;
|
||||||
|
dev = vn_todev(vp);
|
||||||
|
if (dev == NODEV)
|
||||||
|
return EBADF;
|
||||||
|
SMB_CHECKMINOR(dev);
|
||||||
|
ssp = sdp->sd_share;
|
||||||
|
if (ssp == NULL)
|
||||||
|
return ENOTCONN;
|
||||||
|
error = smb_share_get(ssp, LK_EXCLUSIVE, scred);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
*sspp = ssp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
199
sys/netsmb/smb_dev.h
Normal file
199
sys/netsmb/smb_dev.h
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001 Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#ifndef _NETSMB_DEV_H_
|
||||||
|
#define _NETSMB_DEV_H_
|
||||||
|
|
||||||
|
#define NSMB_NAME "nsmb"
|
||||||
|
#define NSMB_MAJOR 144
|
||||||
|
|
||||||
|
#define NSMB_VERMAJ 1
|
||||||
|
#define NSMB_VERMIN 3006
|
||||||
|
#define NSMB_VERSION (NSMB_VERMAJ * 100000 + NSMB_VERMIN)
|
||||||
|
|
||||||
|
#define NSMBFL_OPEN 0x0001
|
||||||
|
|
||||||
|
#define SMBVOPT_CREATE 0x0001 /* create object if necessary */
|
||||||
|
#define SMBVOPT_PRIVATE 0x0002 /* connection should be private */
|
||||||
|
#define SMBVOPT_SINGLESHARE 0x0004 /* keep only ane share at this VC */
|
||||||
|
#define SMBVOPT_PERMANENT 0x0010 /* object will keep last reference */
|
||||||
|
|
||||||
|
#define SMBSOPT_CREATE 0x0001 /* create object if necessary */
|
||||||
|
#define SMBSOPT_PERMANENT 0x0010 /* object will keep last reference */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SMBIOC_LOOKUP flags
|
||||||
|
*/
|
||||||
|
#define SMBLK_CREATE 0x0001
|
||||||
|
|
||||||
|
struct smbioc_ossn {
|
||||||
|
int ioc_opt;
|
||||||
|
int ioc_svlen; /* size of ioc_server address */
|
||||||
|
struct sockaddr*ioc_server;
|
||||||
|
int ioc_lolen; /* size of ioc_local address */
|
||||||
|
struct sockaddr*ioc_local;
|
||||||
|
char ioc_srvname[SMB_MAXSRVNAMELEN + 1];
|
||||||
|
int ioc_timeout;
|
||||||
|
int ioc_retrycount; /* number of retries before giveup */
|
||||||
|
char ioc_localcs[16];/* local charset */
|
||||||
|
char ioc_servercs[16];/* server charset */
|
||||||
|
char ioc_user[SMB_MAXUSERNAMELEN + 1];
|
||||||
|
char ioc_workgroup[SMB_MAXUSERNAMELEN + 1];
|
||||||
|
char ioc_password[SMB_MAXPASSWORDLEN + 1];
|
||||||
|
uid_t ioc_owner; /* proposed owner */
|
||||||
|
gid_t ioc_group; /* proposed group */
|
||||||
|
mode_t ioc_mode; /* desired access mode */
|
||||||
|
mode_t ioc_rights; /* SMBM_* */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smbioc_oshare {
|
||||||
|
int ioc_opt;
|
||||||
|
int ioc_stype; /* share type */
|
||||||
|
char ioc_share[SMB_MAXSHARENAMELEN + 1];
|
||||||
|
char ioc_password[SMB_MAXPASSWORDLEN + 1];
|
||||||
|
uid_t ioc_owner; /* proposed owner of share */
|
||||||
|
gid_t ioc_group; /* proposed group of share */
|
||||||
|
mode_t ioc_mode; /* desired access mode to share */
|
||||||
|
mode_t ioc_rights; /* SMBM_* */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smbioc_rq {
|
||||||
|
u_char ioc_cmd;
|
||||||
|
u_char ioc_twc;
|
||||||
|
void * ioc_twords;
|
||||||
|
u_short ioc_tbc;
|
||||||
|
void * ioc_tbytes;
|
||||||
|
int ioc_rpbufsz;
|
||||||
|
char * ioc_rpbuf;
|
||||||
|
u_char ioc_rwc;
|
||||||
|
u_short ioc_rbc;
|
||||||
|
u_int8_t ioc_errclass;
|
||||||
|
u_int16_t ioc_serror;
|
||||||
|
u_int32_t ioc_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smbioc_t2rq {
|
||||||
|
u_int16_t ioc_setup[3];
|
||||||
|
int ioc_setupcnt;
|
||||||
|
char * ioc_name;
|
||||||
|
u_short ioc_tparamcnt;
|
||||||
|
void * ioc_tparam;
|
||||||
|
u_short ioc_tdatacnt;
|
||||||
|
void * ioc_tdata;
|
||||||
|
u_short ioc_rparamcnt;
|
||||||
|
void * ioc_rparam;
|
||||||
|
u_short ioc_rdatacnt;
|
||||||
|
void * ioc_rdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smbioc_flags {
|
||||||
|
int ioc_level; /* 0 - session, 1 - share */
|
||||||
|
int ioc_mask;
|
||||||
|
int ioc_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smbioc_lookup {
|
||||||
|
int ioc_level;
|
||||||
|
int ioc_flags;
|
||||||
|
struct smbioc_ossn ioc_ssn;
|
||||||
|
struct smbioc_oshare ioc_sh;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smbioc_rw {
|
||||||
|
smbfh ioc_fh;
|
||||||
|
char * ioc_base;
|
||||||
|
off_t ioc_offset;
|
||||||
|
int ioc_cnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device IOCTLs
|
||||||
|
*/
|
||||||
|
#define SMBIOC_OPENSESSION _IOW('n', 100, struct smbioc_ossn)
|
||||||
|
#define SMBIOC_OPENSHARE _IOW('n', 101, struct smbioc_oshare)
|
||||||
|
#define SMBIOC_REQUEST _IOWR('n', 102, struct smbioc_rq)
|
||||||
|
#define SMBIOC_T2RQ _IOWR('n', 103, struct smbioc_t2rq)
|
||||||
|
#define SMBIOC_SETFLAGS _IOW('n', 104, struct smbioc_flags)
|
||||||
|
#define SMBIOC_LOOKUP _IOW('n', 106, struct smbioc_lookup)
|
||||||
|
#define SMBIOC_READ _IOWR('n', 107, struct smbioc_rw)
|
||||||
|
#define SMBIOC_WRITE _IOWR('n', 108, struct smbioc_rw)
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
|
||||||
|
#ifndef LK_SHARED
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IF_QEMPTY(ifq) ((ifq)->ifq_len == 0)
|
||||||
|
|
||||||
|
#define SMBST_CONNECTED 1
|
||||||
|
|
||||||
|
STAILQ_HEAD(smbrqh, smb_rq);
|
||||||
|
|
||||||
|
struct smb_dev {
|
||||||
|
int sd_opened;
|
||||||
|
int sd_level;
|
||||||
|
struct smb_vc * sd_vc; /* reference to VC */
|
||||||
|
struct smb_share *sd_share; /* reference to share if any */
|
||||||
|
int sd_poll;
|
||||||
|
int sd_seq;
|
||||||
|
/* struct ifqueue sd_rdqueue;
|
||||||
|
struct ifqueue sd_wrqueue;
|
||||||
|
struct selinfo sd_pollinfo;
|
||||||
|
struct smbrqh sd_rqlist;
|
||||||
|
struct smbrqh sd_rplist;
|
||||||
|
struct ucred *sd_owner;*/
|
||||||
|
int sd_flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smb_cred;
|
||||||
|
/*
|
||||||
|
* Compound user interface
|
||||||
|
*/
|
||||||
|
int smb_usr_lookup(struct smbioc_lookup *dp, struct smb_cred *scred,
|
||||||
|
struct smb_vc **vcpp, struct smb_share **sspp);
|
||||||
|
int smb_usr_opensession(struct smbioc_ossn *data,
|
||||||
|
struct smb_cred *scred, struct smb_vc **vcpp);
|
||||||
|
int smb_usr_openshare(struct smb_vc *vcp, struct smbioc_oshare *data,
|
||||||
|
struct smb_cred *scred, struct smb_share **sspp);
|
||||||
|
int smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *data,
|
||||||
|
struct smb_cred *scred);
|
||||||
|
int smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *data,
|
||||||
|
struct smb_cred *scred);
|
||||||
|
int smb_dev2share(int fd, int mode, struct smb_cred *scred,
|
||||||
|
struct smb_share **sspp);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _KERNEL */
|
||||||
|
|
||||||
|
#endif /* _NETSMB_DEV_H_ */
|
709
sys/netsmb/smb_iod.c
Normal file
709
sys/netsmb/smb_iod.c
Normal file
@ -0,0 +1,709 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001 Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/kthread.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/mbuf.h>
|
||||||
|
#include <sys/unistd.h>
|
||||||
|
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_rq.h>
|
||||||
|
#include <netsmb/smb_tran.h>
|
||||||
|
#include <netsmb/smb_trantcp.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define SMBIOD_SLEEP_TIMO 2
|
||||||
|
#define SMBIOD_PING_TIMO 60 /* seconds */
|
||||||
|
|
||||||
|
#define SMB_IOD_EVLOCKPTR(iod) (&((iod)->iod_evlock))
|
||||||
|
#define SMB_IOD_EVLOCK(iod) smb_sl_lock(&((iod)->iod_evlock))
|
||||||
|
#define SMB_IOD_EVUNLOCK(iod) smb_sl_unlock(&((iod)->iod_evlock))
|
||||||
|
|
||||||
|
#define SMB_IOD_RQLOCKPTR(iod) (&((iod)->iod_rqlock))
|
||||||
|
#define SMB_IOD_RQLOCK(iod) smb_sl_lock(&((iod)->iod_rqlock))
|
||||||
|
#define SMB_IOD_RQUNLOCK(iod) smb_sl_unlock(&((iod)->iod_rqlock))
|
||||||
|
|
||||||
|
#define smb_iod_wakeup(iod) wakeup(&(iod)->iod_flags)
|
||||||
|
|
||||||
|
|
||||||
|
static MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon");
|
||||||
|
|
||||||
|
static int smb_iod_next;
|
||||||
|
|
||||||
|
static int smb_iod_sendall(struct smbiod *iod);
|
||||||
|
static int smb_iod_disconnect(struct smbiod *iod);
|
||||||
|
static void smb_iod_thread(void *);
|
||||||
|
|
||||||
|
static __inline void
|
||||||
|
smb_iod_rqprocessed(struct smb_rq *rqp, int error)
|
||||||
|
{
|
||||||
|
SMBRQ_SLOCK(rqp);
|
||||||
|
rqp->sr_lerror = error;
|
||||||
|
rqp->sr_rpgen++;
|
||||||
|
rqp->sr_state = SMBRQ_NOTIFIED;
|
||||||
|
wakeup(&rqp->sr_state);
|
||||||
|
SMBRQ_SUNLOCK(rqp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_iod_invrq(struct smbiod *iod)
|
||||||
|
{
|
||||||
|
struct smb_rq *rqp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Invalidate all outstanding requests for this connection
|
||||||
|
*/
|
||||||
|
SMB_IOD_RQLOCK(iod);
|
||||||
|
TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
|
||||||
|
if (rqp->sr_flags & SMBR_INTERNAL)
|
||||||
|
SMBRQ_SUNLOCK(rqp);
|
||||||
|
rqp->sr_flags |= SMBR_RESTART;
|
||||||
|
smb_iod_rqprocessed(rqp, ENOTCONN);
|
||||||
|
}
|
||||||
|
SMB_IOD_RQUNLOCK(iod);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_iod_closetran(struct smbiod *iod)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = iod->iod_vc;
|
||||||
|
struct proc *p = iod->iod_p;
|
||||||
|
|
||||||
|
if (vcp->vc_tdata == NULL)
|
||||||
|
return;
|
||||||
|
SMB_TRAN_DISCONNECT(vcp, p);
|
||||||
|
SMB_TRAN_DONE(vcp, p);
|
||||||
|
vcp->vc_tdata = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_iod_dead(struct smbiod *iod)
|
||||||
|
{
|
||||||
|
iod->iod_state = SMBIOD_ST_DEAD;
|
||||||
|
smb_iod_closetran(iod);
|
||||||
|
smb_iod_invrq(iod);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_iod_connect(struct smbiod *iod)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = iod->iod_vc;
|
||||||
|
struct proc *p = iod->iod_p;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
SMBIODEBUG("%d\n", iod->iod_state);
|
||||||
|
switch(iod->iod_state) {
|
||||||
|
case SMBIOD_ST_VCACTIVE:
|
||||||
|
SMBERROR("called for already opened connection\n");
|
||||||
|
return EISCONN;
|
||||||
|
case SMBIOD_ST_DEAD:
|
||||||
|
return ENOTCONN; /* XXX: last error code ? */
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vcp->vc_genid++;
|
||||||
|
error = 0;
|
||||||
|
itry {
|
||||||
|
ithrow(SMB_TRAN_CREATE(vcp, p));
|
||||||
|
SMBIODEBUG("tcreate\n");
|
||||||
|
if (vcp->vc_laddr) {
|
||||||
|
ithrow(SMB_TRAN_BIND(vcp, vcp->vc_laddr, p));
|
||||||
|
}
|
||||||
|
SMBIODEBUG("tbind\n");
|
||||||
|
ithrow(SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, p));
|
||||||
|
SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags);
|
||||||
|
iod->iod_state = SMBIOD_ST_TRANACTIVE;
|
||||||
|
SMBIODEBUG("tconnect\n");
|
||||||
|
/* vcp->vc_mid = 0;*/
|
||||||
|
ithrow(smb_smb_negotiate(vcp, &iod->iod_scred));
|
||||||
|
SMBIODEBUG("snegotiate\n");
|
||||||
|
ithrow(smb_smb_ssnsetup(vcp, &iod->iod_scred));
|
||||||
|
iod->iod_state = SMBIOD_ST_VCACTIVE;
|
||||||
|
SMBIODEBUG("completed\n");
|
||||||
|
smb_iod_invrq(iod);
|
||||||
|
} icatch(error) {
|
||||||
|
smb_iod_dead(iod);
|
||||||
|
} ifinally {
|
||||||
|
} iendtry;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_iod_disconnect(struct smbiod *iod)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = iod->iod_vc;
|
||||||
|
|
||||||
|
SMBIODEBUG("\n");
|
||||||
|
if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
|
||||||
|
smb_smb_ssnclose(vcp, &iod->iod_scred);
|
||||||
|
iod->iod_state = SMBIOD_ST_TRANACTIVE;
|
||||||
|
}
|
||||||
|
vcp->vc_smbuid = SMB_UID_UNKNOWN;
|
||||||
|
smb_iod_closetran(iod);
|
||||||
|
iod->iod_state = SMBIOD_ST_NOTCONN;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (iod->iod_state != SMBIOD_ST_VCACTIVE) {
|
||||||
|
if (iod->iod_state != SMBIOD_ST_DEAD)
|
||||||
|
return ENOTCONN;
|
||||||
|
iod->iod_state = SMBIOD_ST_RECONNECT;
|
||||||
|
error = smb_iod_connect(iod);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
SMBIODEBUG("tree reconnect\n");
|
||||||
|
SMBS_ST_LOCK(ssp);
|
||||||
|
ssp->ss_flags |= SMBS_RECONNECTING;
|
||||||
|
SMBS_ST_UNLOCK(ssp);
|
||||||
|
error = smb_smb_treeconnect(ssp, &iod->iod_scred);
|
||||||
|
SMBS_ST_LOCK(ssp);
|
||||||
|
ssp->ss_flags &= ~SMBS_RECONNECTING;
|
||||||
|
SMBS_ST_UNLOCK(ssp);
|
||||||
|
wakeup(&ssp->ss_vcgenid);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
struct proc *p = iod->iod_p;
|
||||||
|
struct smb_vc *vcp = iod->iod_vc;
|
||||||
|
struct smb_share *ssp = rqp->sr_share;
|
||||||
|
struct mbuf *m;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
SMBIODEBUG("iod_state = %d\n", iod->iod_state);
|
||||||
|
switch (iod->iod_state) {
|
||||||
|
case SMBIOD_ST_NOTCONN:
|
||||||
|
smb_iod_rqprocessed(rqp, ENOTCONN);
|
||||||
|
return 0;
|
||||||
|
case SMBIOD_ST_DEAD:
|
||||||
|
iod->iod_state = SMBIOD_ST_RECONNECT;
|
||||||
|
return 0;
|
||||||
|
case SMBIOD_ST_RECONNECT:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rqp->sr_sendcnt == 0) {
|
||||||
|
#ifdef movedtoanotherplace
|
||||||
|
if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
*rqp->sr_rqtid = htoles(ssp ? ssp->ss_tid : SMB_TID_UNKNOWN);
|
||||||
|
*rqp->sr_rquid = htoles(vcp ? vcp->vc_smbuid : 0);
|
||||||
|
mb_fixhdr(&rqp->sr_rq);
|
||||||
|
}
|
||||||
|
if (rqp->sr_sendcnt++ > 5) {
|
||||||
|
rqp->sr_flags |= SMBR_RESTART;
|
||||||
|
smb_iod_rqprocessed(rqp, rqp->sr_lerror);
|
||||||
|
/*
|
||||||
|
* If all attempts to send a request failed, then
|
||||||
|
* something is seriously hosed.
|
||||||
|
*/
|
||||||
|
return ENOTCONN;
|
||||||
|
}
|
||||||
|
SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
|
||||||
|
m_dumpm(rqp->sr_rq.mb_top);
|
||||||
|
m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_WAIT);
|
||||||
|
error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, p) : ENOBUFS;
|
||||||
|
if (error == 0) {
|
||||||
|
getnanotime(&rqp->sr_timesent);
|
||||||
|
iod->iod_lastrqsent = rqp->sr_timesent;
|
||||||
|
rqp->sr_flags |= SMBR_SENT;
|
||||||
|
rqp->sr_state = SMBRQ_SENT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Check for fatal errors
|
||||||
|
*/
|
||||||
|
if (SMB_TRAN_FATAL(vcp, error)) {
|
||||||
|
/*
|
||||||
|
* No further attempts should be made
|
||||||
|
*/
|
||||||
|
return ENOTCONN;
|
||||||
|
}
|
||||||
|
if (smb_rq_intr(rqp))
|
||||||
|
smb_iod_rqprocessed(rqp, EINTR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process incoming packets
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
smb_iod_recvall(struct smbiod *iod)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = iod->iod_vc;
|
||||||
|
struct proc *p = iod->iod_p;
|
||||||
|
struct smb_rq *rqp;
|
||||||
|
struct mbuf *m;
|
||||||
|
u_char *hp;
|
||||||
|
u_short mid;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
switch (iod->iod_state) {
|
||||||
|
case SMBIOD_ST_NOTCONN:
|
||||||
|
case SMBIOD_ST_DEAD:
|
||||||
|
case SMBIOD_ST_RECONNECT:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
m = NULL;
|
||||||
|
error = SMB_TRAN_RECV(vcp, &m, p);
|
||||||
|
if (error == EWOULDBLOCK)
|
||||||
|
break;
|
||||||
|
if (SMB_TRAN_FATAL(vcp, error)) {
|
||||||
|
smb_iod_dead(iod);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
if (m == NULL) {
|
||||||
|
SMBERROR("tran return NULL without error\n");
|
||||||
|
error = EPIPE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m = m_pullup(m, SMB_HDRLEN);
|
||||||
|
if (m == NULL)
|
||||||
|
continue; /* wait for a good packet */
|
||||||
|
/*
|
||||||
|
* Now we got an entire and possibly invalid SMB packet.
|
||||||
|
* Be careful while parsing it.
|
||||||
|
*/
|
||||||
|
m_dumpm(m);
|
||||||
|
hp = mtod(m, u_char*);
|
||||||
|
if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) {
|
||||||
|
m_freem(m);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mid = SMB_HDRMID(hp);
|
||||||
|
SMBSDEBUG("mid %04x\n", (u_int)mid);
|
||||||
|
SMB_IOD_RQLOCK(iod);
|
||||||
|
TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
|
||||||
|
if (rqp->sr_mid != mid)
|
||||||
|
continue;
|
||||||
|
SMBRQ_SLOCK(rqp);
|
||||||
|
if (rqp->sr_rp.md_top == NULL) {
|
||||||
|
md_initm(&rqp->sr_rp, m);
|
||||||
|
} else {
|
||||||
|
if (rqp->sr_flags & SMBR_MULTIPACKET) {
|
||||||
|
md_append_record(&rqp->sr_rp, m);
|
||||||
|
} else {
|
||||||
|
SMBRQ_SUNLOCK(rqp);
|
||||||
|
SMBERROR("duplicate response %d (ignored)\n", mid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SMBRQ_SUNLOCK(rqp);
|
||||||
|
smb_iod_rqprocessed(rqp, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SMB_IOD_RQUNLOCK(iod);
|
||||||
|
if (rqp == NULL) {
|
||||||
|
SMBERROR("drop resp with mid %d\n", (u_int)mid);
|
||||||
|
/* smb_printrqlist(vcp);*/
|
||||||
|
m_freem(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* check for interrupts
|
||||||
|
*/
|
||||||
|
SMB_IOD_RQLOCK(iod);
|
||||||
|
TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
|
||||||
|
if (smb_proc_intr(rqp->sr_cred->scr_p)) {
|
||||||
|
smb_iod_rqprocessed(rqp, EINTR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SMB_IOD_RQUNLOCK(iod);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_iod_request(struct smbiod *iod, int event, void *ident)
|
||||||
|
{
|
||||||
|
struct smbiod_event *evp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
SMBIODEBUG("\n");
|
||||||
|
evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK);
|
||||||
|
evp->ev_type = event;
|
||||||
|
evp->ev_ident = ident;
|
||||||
|
SMB_IOD_EVLOCK(iod);
|
||||||
|
STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link);
|
||||||
|
if ((event & SMBIOD_EV_SYNC) == 0) {
|
||||||
|
SMB_IOD_EVUNLOCK(iod);
|
||||||
|
smb_iod_wakeup(iod);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
smb_iod_wakeup(iod);
|
||||||
|
msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0);
|
||||||
|
error = evp->ev_error;
|
||||||
|
free(evp, M_SMBIOD);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Place request in the queue.
|
||||||
|
* Request from smbiod have a high priority.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smb_iod_addrq(struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = rqp->sr_vc;
|
||||||
|
struct smbiod *iod = vcp->vc_iod;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
SMBIODEBUG("\n");
|
||||||
|
if (rqp->sr_cred->scr_p == iod->iod_p) {
|
||||||
|
rqp->sr_flags |= SMBR_INTERNAL;
|
||||||
|
SMB_IOD_RQLOCK(iod);
|
||||||
|
TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link);
|
||||||
|
SMB_IOD_RQUNLOCK(iod);
|
||||||
|
for (;;) {
|
||||||
|
if (smb_iod_sendrq(iod, rqp) != 0) {
|
||||||
|
smb_iod_dead(iod);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* we don't need to lock state field here
|
||||||
|
*/
|
||||||
|
if (rqp->sr_state != SMBRQ_NOTSENT)
|
||||||
|
break;
|
||||||
|
tsleep(&iod->iod_flags, PWAIT, "90sndw", hz);
|
||||||
|
}
|
||||||
|
if (rqp->sr_lerror)
|
||||||
|
smb_iod_removerq(rqp);
|
||||||
|
return rqp->sr_lerror;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (iod->iod_state) {
|
||||||
|
case SMBIOD_ST_NOTCONN:
|
||||||
|
return ENOTCONN;
|
||||||
|
case SMBIOD_ST_DEAD:
|
||||||
|
error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
return EXDEV;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SMB_IOD_RQLOCK(iod);
|
||||||
|
for (;;) {
|
||||||
|
if (vcp->vc_maxmux == 0) {
|
||||||
|
SMBERROR("maxmux == 0\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (iod->iod_muxcnt < vcp->vc_maxmux)
|
||||||
|
break;
|
||||||
|
iod->iod_muxwant++;
|
||||||
|
msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod),
|
||||||
|
PWAIT, "90mux", 0);
|
||||||
|
}
|
||||||
|
iod->iod_muxcnt++;
|
||||||
|
TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
|
||||||
|
SMB_IOD_RQUNLOCK(iod);
|
||||||
|
smb_iod_wakeup(iod);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_iod_removerq(struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = rqp->sr_vc;
|
||||||
|
struct smbiod *iod = vcp->vc_iod;
|
||||||
|
|
||||||
|
SMBIODEBUG("\n");
|
||||||
|
if (rqp->sr_flags & SMBR_INTERNAL) {
|
||||||
|
SMB_IOD_RQLOCK(iod);
|
||||||
|
TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
|
||||||
|
SMB_IOD_RQUNLOCK(iod);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SMB_IOD_RQLOCK(iod);
|
||||||
|
while (rqp->sr_flags & SMBR_XLOCK) {
|
||||||
|
rqp->sr_flags |= SMBR_XLOCKWANT;
|
||||||
|
msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0);
|
||||||
|
}
|
||||||
|
TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
|
||||||
|
iod->iod_muxcnt--;
|
||||||
|
if (iod->iod_muxwant) {
|
||||||
|
iod->iod_muxwant--;
|
||||||
|
wakeup(&iod->iod_muxwant);
|
||||||
|
}
|
||||||
|
SMB_IOD_RQUNLOCK(iod);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_iod_waitrq(struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
struct smbiod *iod = rqp->sr_vc->vc_iod;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
SMBIODEBUG("\n");
|
||||||
|
if (rqp->sr_flags & SMBR_INTERNAL) {
|
||||||
|
for (;;) {
|
||||||
|
smb_iod_sendall(iod);
|
||||||
|
smb_iod_recvall(iod);
|
||||||
|
if (rqp->sr_rpgen != rqp->sr_rplast)
|
||||||
|
break;
|
||||||
|
tsleep(&iod->iod_flags, PWAIT, "90irq", hz);
|
||||||
|
}
|
||||||
|
smb_iod_removerq(rqp);
|
||||||
|
return rqp->sr_lerror;
|
||||||
|
|
||||||
|
}
|
||||||
|
SMBRQ_SLOCK(rqp);
|
||||||
|
if (rqp->sr_rpgen == rqp->sr_rplast)
|
||||||
|
msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0);
|
||||||
|
rqp->sr_rplast++;
|
||||||
|
SMBRQ_SUNLOCK(rqp);
|
||||||
|
error = rqp->sr_lerror;
|
||||||
|
if (rqp->sr_flags & SMBR_MULTIPACKET) {
|
||||||
|
/*
|
||||||
|
* If request should stay in the list, then reinsert it
|
||||||
|
* at the end of queue so other waiters have chance to concur
|
||||||
|
*/
|
||||||
|
SMB_IOD_RQLOCK(iod);
|
||||||
|
TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
|
||||||
|
TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
|
||||||
|
SMB_IOD_RQUNLOCK(iod);
|
||||||
|
} else
|
||||||
|
smb_iod_removerq(rqp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_iod_sendall(struct smbiod *iod)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = iod->iod_vc;
|
||||||
|
struct smb_rq *rqp;
|
||||||
|
struct timespec ts, tstimeout;
|
||||||
|
int herror;
|
||||||
|
|
||||||
|
herror = 0;
|
||||||
|
/*
|
||||||
|
* Loop through the list of requests and send them if possible
|
||||||
|
*/
|
||||||
|
SMB_IOD_RQLOCK(iod);
|
||||||
|
TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
|
||||||
|
switch (rqp->sr_state) {
|
||||||
|
case SMBRQ_NOTSENT:
|
||||||
|
rqp->sr_flags |= SMBR_XLOCK;
|
||||||
|
SMB_IOD_RQUNLOCK(iod);
|
||||||
|
herror = smb_iod_sendrq(iod, rqp);
|
||||||
|
SMB_IOD_RQLOCK(iod);
|
||||||
|
rqp->sr_flags &= ~SMBR_XLOCK;
|
||||||
|
if (rqp->sr_flags & SMBR_XLOCKWANT) {
|
||||||
|
rqp->sr_flags &= ~SMBR_XLOCKWANT;
|
||||||
|
wakeup(rqp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SMBRQ_SENT:
|
||||||
|
SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout);
|
||||||
|
timespecadd(&tstimeout, &tstimeout);
|
||||||
|
getnanotime(&ts);
|
||||||
|
timespecsub(&ts, &tstimeout);
|
||||||
|
if (timespeccmp(&ts, &rqp->sr_timesent, >)) {
|
||||||
|
smb_iod_rqprocessed(rqp, ETIMEDOUT);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if (herror)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SMB_IOD_RQUNLOCK(iod);
|
||||||
|
if (herror == ENOTCONN)
|
||||||
|
smb_iod_dead(iod);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "main" function for smbiod daemon
|
||||||
|
*/
|
||||||
|
static __inline void
|
||||||
|
smb_iod_main(struct smbiod *iod)
|
||||||
|
{
|
||||||
|
/* struct smb_vc *vcp = iod->iod_vc;*/
|
||||||
|
struct smbiod_event *evp;
|
||||||
|
/* struct timespec tsnow;*/
|
||||||
|
int error;
|
||||||
|
|
||||||
|
SMBIODEBUG("\n");
|
||||||
|
error = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check all interesting events
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
SMB_IOD_EVLOCK(iod);
|
||||||
|
evp = STAILQ_FIRST(&iod->iod_evlist);
|
||||||
|
if (evp == NULL) {
|
||||||
|
SMB_IOD_EVUNLOCK(iod);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link);
|
||||||
|
evp->ev_type |= SMBIOD_EV_PROCESSING;
|
||||||
|
SMB_IOD_EVUNLOCK(iod);
|
||||||
|
switch (evp->ev_type & SMBIOD_EV_MASK) {
|
||||||
|
case SMBIOD_EV_CONNECT:
|
||||||
|
iod->iod_state = SMBIOD_ST_RECONNECT;
|
||||||
|
evp->ev_error = smb_iod_connect(iod);
|
||||||
|
break;
|
||||||
|
case SMBIOD_EV_DISCONNECT:
|
||||||
|
evp->ev_error = smb_iod_disconnect(iod);
|
||||||
|
break;
|
||||||
|
case SMBIOD_EV_TREECONNECT:
|
||||||
|
evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident);
|
||||||
|
break;
|
||||||
|
case SMBIOD_EV_SHUTDOWN:
|
||||||
|
iod->iod_flags |= SMBIOD_SHUTDOWN;
|
||||||
|
break;
|
||||||
|
case SMBIOD_EV_NEWRQ:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (evp->ev_type & SMBIOD_EV_SYNC) {
|
||||||
|
SMB_IOD_EVLOCK(iod);
|
||||||
|
wakeup(evp);
|
||||||
|
SMB_IOD_EVUNLOCK(iod);
|
||||||
|
} else
|
||||||
|
free(evp, M_SMBIOD);
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
|
||||||
|
getnanotime(&tsnow);
|
||||||
|
timespecsub(&tsnow, &iod->iod_pingtimo);
|
||||||
|
if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) {
|
||||||
|
smb_smb_echo(vcp, &iod->iod_scred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
smb_iod_sendall(iod);
|
||||||
|
smb_iod_recvall(iod);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef FB_CURRENT
|
||||||
|
#define kthread_create_compat kthread_create2
|
||||||
|
#else
|
||||||
|
#define kthread_create_compat kthread_create
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_iod_thread(void *arg)
|
||||||
|
{
|
||||||
|
struct smbiod *iod = arg;
|
||||||
|
|
||||||
|
mtx_lock(&Giant);
|
||||||
|
smb_makescred(&iod->iod_scred, iod->iod_p, NULL);
|
||||||
|
while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) {
|
||||||
|
smb_iod_main(iod);
|
||||||
|
SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo);
|
||||||
|
/* mtx_unlock(&Giant, MTX_DEF);*/
|
||||||
|
if (iod->iod_flags & SMBIOD_SHUTDOWN)
|
||||||
|
break;
|
||||||
|
tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo);
|
||||||
|
}
|
||||||
|
/* mtx_lock(&Giant, MTX_DEF);*/
|
||||||
|
kthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_iod_create(struct smb_vc *vcp)
|
||||||
|
{
|
||||||
|
struct smbiod *iod;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK);
|
||||||
|
iod->iod_id = smb_iod_next++;
|
||||||
|
iod->iod_state = SMBIOD_ST_NOTCONN;
|
||||||
|
iod->iod_vc = vcp;
|
||||||
|
iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO;
|
||||||
|
iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO;
|
||||||
|
getnanotime(&iod->iod_lastrqsent);
|
||||||
|
vcp->vc_iod = iod;
|
||||||
|
smb_sl_init(&iod->iod_rqlock, "90rql");
|
||||||
|
TAILQ_INIT(&iod->iod_rqlist);
|
||||||
|
smb_sl_init(&iod->iod_evlock, "90evl");
|
||||||
|
STAILQ_INIT(&iod->iod_evlist);
|
||||||
|
error = kthread_create_compat(smb_iod_thread, iod, &iod->iod_p,
|
||||||
|
RFNOWAIT, "smbiod%d", iod->iod_id);
|
||||||
|
if (error) {
|
||||||
|
SMBERROR("can't start smbiod: %d", error);
|
||||||
|
free(iod, M_SMBIOD);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_iod_destroy(struct smbiod *iod)
|
||||||
|
{
|
||||||
|
smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL);
|
||||||
|
mtx_destroy(&iod->iod_rqlock);
|
||||||
|
mtx_destroy(&iod->iod_evlock);
|
||||||
|
free(iod, M_SMBIOD);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_iod_init(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_iod_done(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
752
sys/netsmb/smb_rq.c
Normal file
752
sys/netsmb/smb_rq.c
Normal file
@ -0,0 +1,752 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001, Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/socketvar.h>
|
||||||
|
#include <sys/mbuf.h>
|
||||||
|
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_rq.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
#include <netsmb/smb_tran.h>
|
||||||
|
|
||||||
|
MALLOC_DEFINE(M_SMBRQ, "SMBRQ", "SMB request");
|
||||||
|
|
||||||
|
MODULE_DEPEND(netsmb, libmchain, 1, 1, 1);
|
||||||
|
|
||||||
|
static int smb_rq_reply(struct smb_rq *rqp);
|
||||||
|
static int smb_rq_enqueue(struct smb_rq *rqp);
|
||||||
|
static int smb_rq_getenv(struct smb_connobj *layer,
|
||||||
|
struct smb_vc **vcpp, struct smb_share **sspp);
|
||||||
|
static int smb_rq_new(struct smb_rq *rqp, u_char cmd);
|
||||||
|
static int smb_t2_reply(struct smb_t2rq *t2p);
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_rq_alloc(struct smb_connobj *layer, u_char cmd, struct smb_cred *scred,
|
||||||
|
struct smb_rq **rqpp)
|
||||||
|
{
|
||||||
|
struct smb_rq *rqp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
MALLOC(rqp, struct smb_rq *, sizeof(*rqp), M_SMBRQ, M_WAITOK);
|
||||||
|
if (rqp == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
error = smb_rq_init(rqp, layer, cmd, scred);
|
||||||
|
rqp->sr_flags |= SMBR_ALLOCED;
|
||||||
|
if (error) {
|
||||||
|
smb_rq_done(rqp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
*rqpp = rqp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char tzero[12];
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, u_char cmd,
|
||||||
|
struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
bzero(rqp, sizeof(*rqp));
|
||||||
|
smb_sl_init(&rqp->sr_slock, "srslock");
|
||||||
|
error = smb_rq_getenv(layer, &rqp->sr_vc, &rqp->sr_share);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
error = smb_vc_access(rqp->sr_vc, scred, SMBM_EXEC);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
if (rqp->sr_share) {
|
||||||
|
error = smb_share_access(rqp->sr_share, scred, SMBM_EXEC);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
rqp->sr_cred = scred;
|
||||||
|
rqp->sr_mid = smb_vc_nextmid(rqp->sr_vc);
|
||||||
|
return smb_rq_new(rqp, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_rq_new(struct smb_rq *rqp, u_char cmd)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = rqp->sr_vc;
|
||||||
|
struct mbchain *mbp = &rqp->sr_rq;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
rqp->sr_sendcnt = 0;
|
||||||
|
mb_done(mbp);
|
||||||
|
md_done(&rqp->sr_rp);
|
||||||
|
error = mb_init(mbp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
mb_put_mem(mbp, SMB_SIGNATURE, SMB_SIGLEN, MB_MSYSTEM);
|
||||||
|
mb_put_uint8(mbp, cmd);
|
||||||
|
mb_put_uint32le(mbp, 0); /* DosError */
|
||||||
|
mb_put_uint8(mbp, vcp->vc_hflags);
|
||||||
|
mb_put_uint16le(mbp, vcp->vc_hflags2);
|
||||||
|
mb_put_mem(mbp, tzero, 12, MB_MSYSTEM);
|
||||||
|
rqp->sr_rqtid = (u_int16_t*)mb_reserve(mbp, sizeof(u_int16_t));
|
||||||
|
mb_put_uint16le(mbp, 1 /*scred->sc_p->p_pid & 0xffff*/);
|
||||||
|
rqp->sr_rquid = (u_int16_t*)mb_reserve(mbp, sizeof(u_int16_t));
|
||||||
|
mb_put_uint16le(mbp, rqp->sr_mid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_rq_done(struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
mb_done(&rqp->sr_rq);
|
||||||
|
md_done(&rqp->sr_rp);
|
||||||
|
smb_sl_destroy(&rqp->sr_slock);
|
||||||
|
if (rqp->sr_flags & SMBR_ALLOCED)
|
||||||
|
free(rqp, M_SMBRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple request-reply exchange
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smb_rq_simple(struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = rqp->sr_vc;
|
||||||
|
int error = EINVAL, i;
|
||||||
|
|
||||||
|
for (i = 0; i < SMB_MAXRCN; i++) {
|
||||||
|
rqp->sr_flags &= ~SMBR_RESTART;
|
||||||
|
rqp->sr_timo = vcp->vc_timo;
|
||||||
|
rqp->sr_state = SMBRQ_NOTSENT;
|
||||||
|
error = smb_rq_enqueue(rqp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
error = smb_rq_reply(rqp);
|
||||||
|
if (error == 0)
|
||||||
|
break;
|
||||||
|
if ((rqp->sr_flags & (SMBR_RESTART | SMBR_NORESTART)) != SMBR_RESTART)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_rq_enqueue(struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
struct smb_share *ssp = rqp->sr_share;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (ssp == NULL || rqp->sr_cred == &rqp->sr_vc->vc_iod->iod_scred) {
|
||||||
|
return smb_iod_addrq(rqp);
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
SMBS_ST_LOCK(ssp);
|
||||||
|
if (ssp->ss_flags & SMBS_RECONNECTING) {
|
||||||
|
msleep(&ssp->ss_vcgenid, SMBS_ST_LOCKPTR(ssp),
|
||||||
|
PWAIT | PDROP, "90trcn", hz);
|
||||||
|
if (smb_proc_intr(rqp->sr_cred->scr_p))
|
||||||
|
return EINTR;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (smb_share_valid(ssp) || (ssp->ss_flags & SMBS_CONNECTED) == 0) {
|
||||||
|
SMBS_ST_UNLOCK(ssp);
|
||||||
|
} else {
|
||||||
|
SMBS_ST_UNLOCK(ssp);
|
||||||
|
error = smb_iod_request(rqp->sr_vc->vc_iod,
|
||||||
|
SMBIOD_EV_TREECONNECT | SMBIOD_EV_SYNC, ssp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
error = smb_iod_addrq(rqp);
|
||||||
|
if (error != EXDEV)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_rq_wstart(struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
rqp->sr_wcount = mb_reserve(&rqp->sr_rq, sizeof(u_int8_t));
|
||||||
|
rqp->sr_rq.mb_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_rq_wend(struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
if (rqp->sr_wcount == NULL) {
|
||||||
|
SMBERROR("no wcount\n"); /* actually panic */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rqp->sr_rq.mb_count & 1)
|
||||||
|
SMBERROR("odd word count\n");
|
||||||
|
*rqp->sr_wcount = rqp->sr_rq.mb_count / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_rq_bstart(struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
rqp->sr_bcount = (u_short*)mb_reserve(&rqp->sr_rq, sizeof(u_short));
|
||||||
|
rqp->sr_rq.mb_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_rq_bend(struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
int bcnt;
|
||||||
|
|
||||||
|
if (rqp->sr_bcount == NULL) {
|
||||||
|
SMBERROR("no bcount\n"); /* actually panic */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bcnt = rqp->sr_rq.mb_count;
|
||||||
|
if (bcnt > 0xffff)
|
||||||
|
SMBERROR("byte count too large (%d)\n", bcnt);
|
||||||
|
*rqp->sr_bcount = bcnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_rq_intr(struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
struct proc *p = rqp->sr_cred->scr_p;
|
||||||
|
|
||||||
|
if (rqp->sr_flags & SMBR_INTR)
|
||||||
|
return EINTR;
|
||||||
|
return smb_proc_intr(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp)
|
||||||
|
{
|
||||||
|
*mbpp = &rqp->sr_rq;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp)
|
||||||
|
{
|
||||||
|
*mbpp = &rqp->sr_rp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_rq_getenv(struct smb_connobj *layer,
|
||||||
|
struct smb_vc **vcpp, struct smb_share **sspp)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = NULL;
|
||||||
|
struct smb_share *ssp = NULL;
|
||||||
|
struct smb_connobj *cp;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
switch (layer->co_level) {
|
||||||
|
case SMBL_VC:
|
||||||
|
vcp = CPTOVC(layer);
|
||||||
|
if (layer->co_parent == NULL) {
|
||||||
|
SMBERROR("zombie VC %s\n", vcp->vc_srvname);
|
||||||
|
error = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SMBL_SHARE:
|
||||||
|
ssp = CPTOSS(layer);
|
||||||
|
cp = layer->co_parent;
|
||||||
|
if (cp == NULL) {
|
||||||
|
SMBERROR("zombie share %s\n", ssp->ss_name);
|
||||||
|
error = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
error = smb_rq_getenv(cp, &vcp, NULL);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SMBERROR("invalid layer %d passed\n", layer->co_level);
|
||||||
|
error = EINVAL;
|
||||||
|
}
|
||||||
|
if (vcpp)
|
||||||
|
*vcpp = vcp;
|
||||||
|
if (sspp)
|
||||||
|
*sspp = ssp;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for reply on the request
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
smb_rq_reply(struct smb_rq *rqp)
|
||||||
|
{
|
||||||
|
struct mdchain *mdp = &rqp->sr_rp;
|
||||||
|
u_int32_t tdw;
|
||||||
|
u_int8_t tb;
|
||||||
|
int error, rperror = 0;
|
||||||
|
|
||||||
|
error = smb_iod_waitrq(rqp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
error = md_get_uint32(mdp, &tdw);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
error = md_get_uint8(mdp, &tb);
|
||||||
|
if (rqp->sr_vc->vc_hflags2 & SMB_FLAGS2_ERR_STATUS) {
|
||||||
|
error = md_get_uint32le(mdp, &rqp->sr_error);
|
||||||
|
} else {
|
||||||
|
error = md_get_uint8(mdp, &rqp->sr_errclass);
|
||||||
|
error = md_get_uint8(mdp, &tb);
|
||||||
|
error = md_get_uint16le(mdp, &rqp->sr_serror);
|
||||||
|
if (!error)
|
||||||
|
rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
|
||||||
|
}
|
||||||
|
error = md_get_uint8(mdp, &rqp->sr_rpflags);
|
||||||
|
error = md_get_uint16le(mdp, &rqp->sr_rpflags2);
|
||||||
|
|
||||||
|
error = md_get_uint32(mdp, &tdw);
|
||||||
|
error = md_get_uint32(mdp, &tdw);
|
||||||
|
error = md_get_uint32(mdp, &tdw);
|
||||||
|
|
||||||
|
error = md_get_uint16le(mdp, &rqp->sr_rptid);
|
||||||
|
error = md_get_uint16le(mdp, &rqp->sr_rppid);
|
||||||
|
error = md_get_uint16le(mdp, &rqp->sr_rpuid);
|
||||||
|
error = md_get_uint16le(mdp, &rqp->sr_rpmid);
|
||||||
|
|
||||||
|
SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x, E: %d:%d\n",
|
||||||
|
rqp->sr_rpmid, rqp->sr_rppid, rqp->sr_rpuid, rqp->sr_rptid,
|
||||||
|
rqp->sr_errclass, rqp->sr_serror);
|
||||||
|
return error ? error : rperror;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define ALIGN4(a) (((a) + 3) & ~3)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TRANS2 request implementation
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smb_t2_alloc(struct smb_connobj *layer, u_short setup, struct smb_cred *scred,
|
||||||
|
struct smb_t2rq **t2pp)
|
||||||
|
{
|
||||||
|
struct smb_t2rq *t2p;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
MALLOC(t2p, struct smb_t2rq *, sizeof(*t2p), M_SMBRQ, M_WAITOK);
|
||||||
|
if (t2p == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
error = smb_t2_init(t2p, layer, setup, scred);
|
||||||
|
t2p->t2_flags |= SMBT2_ALLOCED;
|
||||||
|
if (error) {
|
||||||
|
smb_t2_done(t2p);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
*t2pp = t2p;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_t2_init(struct smb_t2rq *t2p, struct smb_connobj *source, u_short setup,
|
||||||
|
struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
bzero(t2p, sizeof(*t2p));
|
||||||
|
t2p->t2_source = source;
|
||||||
|
t2p->t2_setupcount = 1;
|
||||||
|
t2p->t2_setupdata = t2p->t2_setup;
|
||||||
|
t2p->t2_setup[0] = setup;
|
||||||
|
t2p->t2_fid = 0xffff;
|
||||||
|
t2p->t2_cred = scred;
|
||||||
|
error = smb_rq_getenv(source, &t2p->t2_vc, NULL);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_t2_done(struct smb_t2rq *t2p)
|
||||||
|
{
|
||||||
|
mb_done(&t2p->t2_tparam);
|
||||||
|
mb_done(&t2p->t2_tdata);
|
||||||
|
md_done(&t2p->t2_rparam);
|
||||||
|
md_done(&t2p->t2_rdata);
|
||||||
|
if (t2p->t2_flags & SMBT2_ALLOCED)
|
||||||
|
free(t2p, M_SMBRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_t2_placedata(struct mbuf *mtop, u_int16_t offset, u_int16_t count,
|
||||||
|
struct mdchain *mdp)
|
||||||
|
{
|
||||||
|
struct mbuf *m, *m0;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
m0 = m_split(mtop, offset, M_WAIT);
|
||||||
|
if (m0 == NULL)
|
||||||
|
return EBADRPC;
|
||||||
|
for(len = 0, m = m0; m->m_next; m = m->m_next)
|
||||||
|
len += m->m_len;
|
||||||
|
len += m->m_len;
|
||||||
|
m->m_len -= len - count;
|
||||||
|
if (mdp->md_top == NULL) {
|
||||||
|
md_initm(mdp, m0);
|
||||||
|
} else
|
||||||
|
m_cat(mdp->md_top, m0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_t2_reply(struct smb_t2rq *t2p)
|
||||||
|
{
|
||||||
|
struct mdchain *mdp;
|
||||||
|
struct smb_rq *rqp = t2p->t2_rq;
|
||||||
|
int error, totpgot, totdgot;
|
||||||
|
u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp;
|
||||||
|
u_int16_t tmp, bc, dcount;
|
||||||
|
u_int8_t wc;
|
||||||
|
|
||||||
|
error = smb_rq_reply(rqp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
if ((t2p->t2_flags & SMBT2_ALLSENT) == 0) {
|
||||||
|
/*
|
||||||
|
* this is an interim response, ignore it.
|
||||||
|
*/
|
||||||
|
SMBRQ_SLOCK(rqp);
|
||||||
|
md_next_record(&rqp->sr_rp);
|
||||||
|
SMBRQ_SUNLOCK(rqp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Now we have to get all subseqent responses. The CIFS specification
|
||||||
|
* says that they can be misordered which is weird.
|
||||||
|
* TODO: timo
|
||||||
|
*/
|
||||||
|
totpgot = totdgot = 0;
|
||||||
|
totpcount = totdcount = 0xffff;
|
||||||
|
mdp = &rqp->sr_rp;
|
||||||
|
for (;;) {
|
||||||
|
m_dumpm(mdp->md_top);
|
||||||
|
if ((error = md_get_uint8(mdp, &wc)) != 0)
|
||||||
|
break;
|
||||||
|
if (wc < 10) {
|
||||||
|
error = ENOENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((error = md_get_uint16le(mdp, &tmp)) != 0)
|
||||||
|
break;
|
||||||
|
if (totpcount > tmp)
|
||||||
|
totpcount = tmp;
|
||||||
|
md_get_uint16le(mdp, &tmp);
|
||||||
|
if (totdcount > tmp)
|
||||||
|
totdcount = tmp;
|
||||||
|
if ((error = md_get_uint16le(mdp, &tmp)) != 0 || /* reserved */
|
||||||
|
(error = md_get_uint16le(mdp, &pcount)) != 0 ||
|
||||||
|
(error = md_get_uint16le(mdp, &poff)) != 0 ||
|
||||||
|
(error = md_get_uint16le(mdp, &pdisp)) != 0)
|
||||||
|
break;
|
||||||
|
if (pcount != 0 && pdisp != totpgot) {
|
||||||
|
SMBERROR("Can't handle misordered parameters %d:%d\n",
|
||||||
|
pdisp, totpgot);
|
||||||
|
error = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((error = md_get_uint16le(mdp, &dcount)) != 0 ||
|
||||||
|
(error = md_get_uint16le(mdp, &doff)) != 0 ||
|
||||||
|
(error = md_get_uint16le(mdp, &ddisp)) != 0)
|
||||||
|
break;
|
||||||
|
if (dcount != 0 && ddisp != totdgot) {
|
||||||
|
SMBERROR("Can't handle misordered data\n");
|
||||||
|
error = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
md_get_uint8(mdp, &wc);
|
||||||
|
md_get_uint8(mdp, NULL);
|
||||||
|
tmp = wc;
|
||||||
|
while (tmp--)
|
||||||
|
md_get_uint16(mdp, NULL);
|
||||||
|
if ((error = md_get_uint16le(mdp, &bc)) != 0)
|
||||||
|
break;
|
||||||
|
/* tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/
|
||||||
|
if (dcount) {
|
||||||
|
error = smb_t2_placedata(mdp->md_top, doff, dcount,
|
||||||
|
&t2p->t2_rdata);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pcount) {
|
||||||
|
error = smb_t2_placedata(mdp->md_top, poff, pcount,
|
||||||
|
&t2p->t2_rparam);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
totpgot += pcount;
|
||||||
|
totdgot += dcount;
|
||||||
|
if (totpgot >= totpcount && totdgot >= totdcount) {
|
||||||
|
error = 0;
|
||||||
|
t2p->t2_flags |= SMBT2_ALLRECV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We're done with this reply, look for the next one.
|
||||||
|
*/
|
||||||
|
SMBRQ_SLOCK(rqp);
|
||||||
|
md_next_record(&rqp->sr_rp);
|
||||||
|
SMBRQ_SUNLOCK(rqp);
|
||||||
|
error = smb_rq_reply(rqp);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform a full round of TRANS2 request
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
smb_t2_request_int(struct smb_t2rq *t2p)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = t2p->t2_vc;
|
||||||
|
struct smb_cred *scred = t2p->t2_cred;
|
||||||
|
struct mbchain *mbp;
|
||||||
|
struct mdchain *mdp, mbparam, mbdata;
|
||||||
|
struct mbuf *m;
|
||||||
|
struct smb_rq *rqp;
|
||||||
|
int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i;
|
||||||
|
int error, doff, poff, txdcount, txpcount, nmlen;
|
||||||
|
|
||||||
|
m = t2p->t2_tparam.mb_top;
|
||||||
|
if (m) {
|
||||||
|
md_initm(&mbparam, m); /* do not free it! */
|
||||||
|
totpcount = m_fixhdr(m);
|
||||||
|
if (totpcount > 0xffff) /* maxvalue for u_short */
|
||||||
|
return EINVAL;
|
||||||
|
} else
|
||||||
|
totpcount = 0;
|
||||||
|
m = t2p->t2_tdata.mb_top;
|
||||||
|
if (m) {
|
||||||
|
md_initm(&mbdata, m); /* do not free it! */
|
||||||
|
totdcount = m_fixhdr(m);
|
||||||
|
if (totdcount > 0xffff)
|
||||||
|
return EINVAL;
|
||||||
|
} else
|
||||||
|
totdcount = 0;
|
||||||
|
leftdcount = totdcount;
|
||||||
|
leftpcount = totpcount;
|
||||||
|
txmax = vcp->vc_txmax;
|
||||||
|
error = smb_rq_alloc(t2p->t2_source, t2p->t_name ?
|
||||||
|
SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
rqp->sr_flags |= SMBR_MULTIPACKET;
|
||||||
|
t2p->t2_rq = rqp;
|
||||||
|
mbp = &rqp->sr_rq;
|
||||||
|
smb_rq_wstart(rqp);
|
||||||
|
mb_put_uint16le(mbp, totpcount);
|
||||||
|
mb_put_uint16le(mbp, totdcount);
|
||||||
|
mb_put_uint16le(mbp, t2p->t2_maxpcount);
|
||||||
|
mb_put_uint16le(mbp, t2p->t2_maxdcount);
|
||||||
|
mb_put_uint8(mbp, t2p->t2_maxscount);
|
||||||
|
mb_put_uint8(mbp, 0); /* reserved */
|
||||||
|
mb_put_uint16le(mbp, 0); /* flags */
|
||||||
|
mb_put_uint32le(mbp, 0); /* Timeout */
|
||||||
|
mb_put_uint16le(mbp, 0); /* reserved 2 */
|
||||||
|
len = mb_fixhdr(mbp);
|
||||||
|
/*
|
||||||
|
* now we have known packet size as
|
||||||
|
* ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1),
|
||||||
|
* and need to decide which parts should go into the first request
|
||||||
|
*/
|
||||||
|
nmlen = t2p->t_name ? strlen(t2p->t_name) : 0;
|
||||||
|
len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmlen + 1);
|
||||||
|
if (len + leftpcount > txmax) {
|
||||||
|
txpcount = min(leftpcount, txmax - len);
|
||||||
|
poff = len;
|
||||||
|
txdcount = 0;
|
||||||
|
doff = 0;
|
||||||
|
} else {
|
||||||
|
txpcount = leftpcount;
|
||||||
|
poff = txpcount ? len : 0;
|
||||||
|
len = ALIGN4(len + txpcount);
|
||||||
|
txdcount = min(leftdcount, txmax - len);
|
||||||
|
doff = txdcount ? len : 0;
|
||||||
|
}
|
||||||
|
leftpcount -= txpcount;
|
||||||
|
leftdcount -= txdcount;
|
||||||
|
mb_put_uint16le(mbp, txpcount);
|
||||||
|
mb_put_uint16le(mbp, poff);
|
||||||
|
mb_put_uint16le(mbp, txdcount);
|
||||||
|
mb_put_uint16le(mbp, doff);
|
||||||
|
mb_put_uint8(mbp, t2p->t2_setupcount);
|
||||||
|
mb_put_uint8(mbp, 0);
|
||||||
|
for (i = 0; i < t2p->t2_setupcount; i++)
|
||||||
|
mb_put_uint16le(mbp, t2p->t2_setupdata[i]);
|
||||||
|
smb_rq_wend(rqp);
|
||||||
|
smb_rq_bstart(rqp);
|
||||||
|
/* TDUNICODE */
|
||||||
|
if (t2p->t_name)
|
||||||
|
mb_put_mem(mbp, t2p->t_name, nmlen, MB_MSYSTEM);
|
||||||
|
mb_put_uint8(mbp, 0); /* terminating zero */
|
||||||
|
len = mb_fixhdr(mbp);
|
||||||
|
if (txpcount) {
|
||||||
|
mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
|
||||||
|
error = md_get_mbuf(&mbparam, txpcount, &m);
|
||||||
|
SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax);
|
||||||
|
if (error)
|
||||||
|
goto freerq;
|
||||||
|
mb_put_mbuf(mbp, m);
|
||||||
|
}
|
||||||
|
len = mb_fixhdr(mbp);
|
||||||
|
if (txdcount) {
|
||||||
|
mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
|
||||||
|
error = md_get_mbuf(&mbdata, txdcount, &m);
|
||||||
|
if (error)
|
||||||
|
goto freerq;
|
||||||
|
mb_put_mbuf(mbp, m);
|
||||||
|
}
|
||||||
|
smb_rq_bend(rqp); /* incredible, but thats it... */
|
||||||
|
error = smb_rq_enqueue(rqp);
|
||||||
|
if (error)
|
||||||
|
goto freerq;
|
||||||
|
if (leftpcount == 0 && leftdcount == 0)
|
||||||
|
t2p->t2_flags |= SMBT2_ALLSENT;
|
||||||
|
error = smb_t2_reply(t2p);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
while (leftpcount || leftdcount) {
|
||||||
|
error = smb_rq_new(rqp, t2p->t_name ?
|
||||||
|
SMB_COM_TRANSACTION_SECONDARY : SMB_COM_TRANSACTION2_SECONDARY);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
mbp = &rqp->sr_rq;
|
||||||
|
smb_rq_wstart(rqp);
|
||||||
|
mb_put_uint16le(mbp, totpcount);
|
||||||
|
mb_put_uint16le(mbp, totdcount);
|
||||||
|
len = mb_fixhdr(mbp);
|
||||||
|
/*
|
||||||
|
* now we have known packet size as
|
||||||
|
* ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one,
|
||||||
|
* and need to decide which parts should go into request
|
||||||
|
*/
|
||||||
|
len = ALIGN4(len + 6 * 2 + 2);
|
||||||
|
if (t2p->t_name == NULL)
|
||||||
|
len += 2;
|
||||||
|
if (len + leftpcount > txmax) {
|
||||||
|
txpcount = min(leftpcount, txmax - len);
|
||||||
|
poff = len;
|
||||||
|
txdcount = 0;
|
||||||
|
doff = 0;
|
||||||
|
} else {
|
||||||
|
txpcount = leftpcount;
|
||||||
|
poff = txpcount ? len : 0;
|
||||||
|
len = ALIGN4(len + txpcount);
|
||||||
|
txdcount = min(leftdcount, txmax - len);
|
||||||
|
doff = txdcount ? len : 0;
|
||||||
|
}
|
||||||
|
mb_put_uint16le(mbp, txpcount);
|
||||||
|
mb_put_uint16le(mbp, poff);
|
||||||
|
mb_put_uint16le(mbp, totpcount - leftpcount);
|
||||||
|
mb_put_uint16le(mbp, txdcount);
|
||||||
|
mb_put_uint16le(mbp, doff);
|
||||||
|
mb_put_uint16le(mbp, totdcount - leftdcount);
|
||||||
|
leftpcount -= txpcount;
|
||||||
|
leftdcount -= txdcount;
|
||||||
|
if (t2p->t_name == NULL)
|
||||||
|
mb_put_uint16le(mbp, t2p->t2_fid);
|
||||||
|
smb_rq_wend(rqp);
|
||||||
|
smb_rq_bstart(rqp);
|
||||||
|
mb_put_uint8(mbp, 0); /* name */
|
||||||
|
len = mb_fixhdr(mbp);
|
||||||
|
if (txpcount) {
|
||||||
|
mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
|
||||||
|
error = md_get_mbuf(&mbparam, txpcount, &m);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
mb_put_mbuf(mbp, m);
|
||||||
|
}
|
||||||
|
len = mb_fixhdr(mbp);
|
||||||
|
if (txdcount) {
|
||||||
|
mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
|
||||||
|
error = md_get_mbuf(&mbdata, txdcount, &m);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
mb_put_mbuf(mbp, m);
|
||||||
|
}
|
||||||
|
smb_rq_bend(rqp);
|
||||||
|
rqp->sr_state = SMBRQ_NOTSENT;
|
||||||
|
error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_NEWRQ, NULL);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
} /* while left params or data */
|
||||||
|
t2p->t2_flags |= SMBT2_ALLSENT;
|
||||||
|
mdp = &t2p->t2_rdata;
|
||||||
|
if (mdp->md_top) {
|
||||||
|
m_fixhdr(mdp->md_top);
|
||||||
|
md_initm(mdp, mdp->md_top);
|
||||||
|
}
|
||||||
|
mdp = &t2p->t2_rparam;
|
||||||
|
if (mdp->md_top) {
|
||||||
|
m_fixhdr(mdp->md_top);
|
||||||
|
md_initm(mdp, mdp->md_top);
|
||||||
|
}
|
||||||
|
bad:
|
||||||
|
smb_iod_removerq(rqp);
|
||||||
|
freerq:
|
||||||
|
smb_rq_done(rqp);
|
||||||
|
if (error) {
|
||||||
|
if (rqp->sr_flags & SMBR_RESTART)
|
||||||
|
t2p->t2_flags |= SMBT2_RESTART;
|
||||||
|
md_done(&t2p->t2_rparam);
|
||||||
|
md_done(&t2p->t2_rdata);
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_t2_request(struct smb_t2rq *t2p)
|
||||||
|
{
|
||||||
|
int error = EINVAL, i;
|
||||||
|
|
||||||
|
for (i = 0; i < SMB_MAXRCN; i++) {
|
||||||
|
t2p->t2_flags &= ~SMBR_RESTART;
|
||||||
|
error = smb_t2_request_int(t2p);
|
||||||
|
if (error == 0)
|
||||||
|
break;
|
||||||
|
if ((t2p->t2_flags & (SMBT2_RESTART | SMBT2_NORESTART)) != SMBT2_RESTART)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
151
sys/netsmb/smb_rq.h
Normal file
151
sys/netsmb/smb_rq.h
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001, Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#ifndef _NETSMB_SMB_RQ_H_
|
||||||
|
#define _NETSMB_SMB_RQ_H_
|
||||||
|
|
||||||
|
#ifndef MB_MSYSTEM
|
||||||
|
#include <sys/mchain.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SMBR_ALLOCED 0x0001 /* structure was malloced */
|
||||||
|
#define SMBR_SENT 0x0002 /* request successfully transmitted */
|
||||||
|
#define SMBR_REXMIT 0x0004 /* request should be retransmitted */
|
||||||
|
#define SMBR_INTR 0x0008 /* request interrupted */
|
||||||
|
#define SMBR_RESTART 0x0010 /* request should be repeated if possible */
|
||||||
|
#define SMBR_NORESTART 0x0020 /* request is not restartable */
|
||||||
|
#define SMBR_MULTIPACKET 0x0040 /* multiple packets can be sent and received */
|
||||||
|
#define SMBR_INTERNAL 0x0080 /* request is internal to smbrqd */
|
||||||
|
#define SMBR_XLOCK 0x0100 /* request locked and can't be moved */
|
||||||
|
#define SMBR_XLOCKWANT 0x0200 /* waiter on XLOCK */
|
||||||
|
|
||||||
|
#define SMBT2_ALLSENT 0x0001 /* all data and params are sent */
|
||||||
|
#define SMBT2_ALLRECV 0x0002 /* all data and params are received */
|
||||||
|
#define SMBT2_ALLOCED 0x0004
|
||||||
|
#define SMBT2_RESTART 0x0008
|
||||||
|
#define SMBT2_NORESTART 0x0010
|
||||||
|
|
||||||
|
#define SMBRQ_SLOCK(rqp) smb_sl_lock(&(rqp)->sr_slock)
|
||||||
|
#define SMBRQ_SUNLOCK(rqp) smb_sl_unlock(&(rqp)->sr_slock)
|
||||||
|
#define SMBRQ_SLOCKPTR(rqp) (&(rqp)->sr_slock)
|
||||||
|
|
||||||
|
|
||||||
|
enum smbrq_state {
|
||||||
|
SMBRQ_NOTSENT, /* rq have data to send */
|
||||||
|
SMBRQ_SENT, /* send procedure completed */
|
||||||
|
SMBRQ_REPLYRECEIVED,
|
||||||
|
SMBRQ_NOTIFIED /* owner notified about completion */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smb_vc;
|
||||||
|
struct smb_t2rq;
|
||||||
|
|
||||||
|
struct smb_rq {
|
||||||
|
enum smbrq_state sr_state;
|
||||||
|
struct smb_vc * sr_vc;
|
||||||
|
struct smb_share* sr_share;
|
||||||
|
u_short sr_mid;
|
||||||
|
struct mbchain sr_rq;
|
||||||
|
u_int8_t sr_rqflags;
|
||||||
|
u_int16_t sr_rqflags2;
|
||||||
|
u_char * sr_wcount;
|
||||||
|
u_short * sr_bcount;
|
||||||
|
struct mdchain sr_rp;
|
||||||
|
int sr_rpgen;
|
||||||
|
int sr_rplast;
|
||||||
|
int sr_flags; /* SMBR_* */
|
||||||
|
int sr_rpsize;
|
||||||
|
struct smb_cred * sr_cred;
|
||||||
|
int sr_timo;
|
||||||
|
int sr_rexmit;
|
||||||
|
int sr_sendcnt;
|
||||||
|
struct timespec sr_timesent;
|
||||||
|
int sr_lerror;
|
||||||
|
u_int16_t * sr_rqtid;
|
||||||
|
u_int16_t * sr_rquid;
|
||||||
|
u_int8_t sr_errclass;
|
||||||
|
u_int16_t sr_serror;
|
||||||
|
u_int32_t sr_error;
|
||||||
|
u_int8_t sr_rpflags;
|
||||||
|
u_int16_t sr_rpflags2;
|
||||||
|
u_int16_t sr_rptid;
|
||||||
|
u_int16_t sr_rppid;
|
||||||
|
u_int16_t sr_rpuid;
|
||||||
|
u_int16_t sr_rpmid;
|
||||||
|
struct smb_slock sr_slock; /* short term locks */
|
||||||
|
/* struct smb_t2rq*sr_t2;*/
|
||||||
|
TAILQ_ENTRY(smb_rq) sr_link;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct smb_t2rq {
|
||||||
|
u_int16_t t2_setupcount;
|
||||||
|
u_int16_t * t2_setupdata;
|
||||||
|
u_int16_t t2_setup[2]; /* most of rqs has setupcount of 1 */
|
||||||
|
u_int8_t t2_maxscount; /* max setup words to return */
|
||||||
|
u_int16_t t2_maxpcount; /* max param bytes to return */
|
||||||
|
u_int16_t t2_maxdcount; /* max data bytes to return */
|
||||||
|
u_int16_t t2_fid; /* for T2 request */
|
||||||
|
char * t_name; /* for T request, should be zero for T2 */
|
||||||
|
int t2_flags; /* SMBT2_ */
|
||||||
|
struct mbchain t2_tparam; /* parameters to transmit */
|
||||||
|
struct mbchain t2_tdata; /* data to transmit */
|
||||||
|
struct mdchain t2_rparam; /* received paramters */
|
||||||
|
struct mdchain t2_rdata; /* received data */
|
||||||
|
struct smb_cred*t2_cred;
|
||||||
|
struct smb_connobj *t2_source;
|
||||||
|
struct smb_rq * t2_rq;
|
||||||
|
struct smb_vc * t2_vc;
|
||||||
|
};
|
||||||
|
|
||||||
|
int smb_rq_alloc(struct smb_connobj *layer, u_char cmd,
|
||||||
|
struct smb_cred *scred, struct smb_rq **rqpp);
|
||||||
|
int smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, u_char cmd,
|
||||||
|
struct smb_cred *scred);
|
||||||
|
void smb_rq_done(struct smb_rq *rqp);
|
||||||
|
int smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp);
|
||||||
|
int smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp);
|
||||||
|
void smb_rq_wstart(struct smb_rq *rqp);
|
||||||
|
void smb_rq_wend(struct smb_rq *rqp);
|
||||||
|
void smb_rq_bstart(struct smb_rq *rqp);
|
||||||
|
void smb_rq_bend(struct smb_rq *rqp);
|
||||||
|
int smb_rq_intr(struct smb_rq *rqp);
|
||||||
|
int smb_rq_simple(struct smb_rq *rqp);
|
||||||
|
|
||||||
|
int smb_t2_alloc(struct smb_connobj *layer, u_short setup, struct smb_cred *scred,
|
||||||
|
struct smb_t2rq **rqpp);
|
||||||
|
int smb_t2_init(struct smb_t2rq *rqp, struct smb_connobj *layer, u_short setup,
|
||||||
|
struct smb_cred *scred);
|
||||||
|
void smb_t2_done(struct smb_t2rq *t2p);
|
||||||
|
int smb_t2_request(struct smb_t2rq *t2p);
|
||||||
|
|
||||||
|
#endif /* !_NETSMB_SMB_RQ_H_ */
|
660
sys/netsmb/smb_smb.c
Normal file
660
sys/netsmb/smb_smb.c
Normal file
@ -0,0 +1,660 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001 Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* various SMB requests. Most of the routines merely packs data into mbufs.
|
||||||
|
*/
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
#include <sys/iconv.h>
|
||||||
|
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
#include <netsmb/smb_rq.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_tran.h>
|
||||||
|
|
||||||
|
struct smb_dialect {
|
||||||
|
int d_id;
|
||||||
|
const char * d_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct smb_dialect smb_dialects[] = {
|
||||||
|
{SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"},
|
||||||
|
{SMB_DIALECT_COREPLUS, "MICROSOFT NETWORKS 1.03"},
|
||||||
|
{SMB_DIALECT_LANMAN1_0, "MICROSOFT NETWORKS 3.0"},
|
||||||
|
{SMB_DIALECT_LANMAN1_0, "LANMAN1.0"},
|
||||||
|
{SMB_DIALECT_LANMAN2_0, "LM1.2X002"},
|
||||||
|
{SMB_DIALECT_LANMAN2_0, "Samba"},
|
||||||
|
{SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"},
|
||||||
|
{SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
|
||||||
|
{-1, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SMB_DIALECT_MAX (sizeof(smb_dialects) / sizeof(struct smb_dialect) - 2)
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_smb_nomux(struct smb_vc *vcp, struct smb_cred *scred, const char *name)
|
||||||
|
{
|
||||||
|
if (scred->scr_p == vcp->vc_iod->iod_p)
|
||||||
|
return 0;
|
||||||
|
SMBERROR("wrong function called(%s)\n", name);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_dialect *dp;
|
||||||
|
struct smb_sopt *sp = NULL;
|
||||||
|
struct smb_rq *rqp;
|
||||||
|
struct mbchain *mbp;
|
||||||
|
struct mdchain *mdp;
|
||||||
|
u_int8_t wc, stime[8], sblen;
|
||||||
|
u_int16_t dindex, tw, tw1, swlen, bc;
|
||||||
|
int error, maxqsz;
|
||||||
|
|
||||||
|
if (smb_smb_nomux(vcp, scred, __FUNCTION__) != 0)
|
||||||
|
return EINVAL;
|
||||||
|
vcp->vc_hflags = 0;
|
||||||
|
vcp->vc_hflags2 = 0;
|
||||||
|
vcp->obj.co_flags &= ~(SMBV_ENCRYPT);
|
||||||
|
sp = &vcp->vc_sopt;
|
||||||
|
bzero(sp, sizeof(struct smb_sopt));
|
||||||
|
error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
smb_rq_getrequest(rqp, &mbp);
|
||||||
|
smb_rq_wstart(rqp);
|
||||||
|
smb_rq_wend(rqp);
|
||||||
|
smb_rq_bstart(rqp);
|
||||||
|
for(dp = smb_dialects; dp->d_id != -1; dp++) {
|
||||||
|
mb_put_uint8(mbp, SMB_DT_DIALECT);
|
||||||
|
smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE);
|
||||||
|
}
|
||||||
|
smb_rq_bend(rqp);
|
||||||
|
error = smb_rq_simple(rqp);
|
||||||
|
SMBSDEBUG("%d\n", error);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
smb_rq_getreply(rqp, &mdp);
|
||||||
|
do {
|
||||||
|
error = md_get_uint8(mdp, &wc);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
error = md_get_uint16le(mdp, &dindex);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
if (dindex > 7) {
|
||||||
|
SMBERROR("Don't know how to talk with server %s (%d)\n", "xxx", dindex);
|
||||||
|
error = EBADRPC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dp = smb_dialects + dindex;
|
||||||
|
sp->sv_proto = dp->d_id;
|
||||||
|
SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc);
|
||||||
|
error = EBADRPC;
|
||||||
|
if (dp->d_id >= SMB_DIALECT_NTLM0_12) {
|
||||||
|
if (wc != 17)
|
||||||
|
break;
|
||||||
|
md_get_uint8(mdp, &sp->sv_sm);
|
||||||
|
md_get_uint16le(mdp, &sp->sv_maxmux);
|
||||||
|
md_get_uint16le(mdp, &sp->sv_maxvcs);
|
||||||
|
md_get_uint32le(mdp, &sp->sv_maxtx);
|
||||||
|
md_get_uint32le(mdp, &sp->sv_maxraw);
|
||||||
|
md_get_uint32le(mdp, &sp->sv_skey);
|
||||||
|
md_get_uint32le(mdp, &sp->sv_caps);
|
||||||
|
md_get_mem(mdp, stime, 8, MB_MSYSTEM);
|
||||||
|
md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz);
|
||||||
|
md_get_uint8(mdp, &sblen);
|
||||||
|
if (sblen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
|
||||||
|
if (sblen != SMB_MAXCHALLENGELEN) {
|
||||||
|
SMBERROR("Unexpected length of security blob (%d)\n", sblen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
error = md_get_uint16(mdp, &bc);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
if (sp->sv_caps & SMB_CAP_EXT_SECURITY)
|
||||||
|
md_get_mem(mdp, NULL, 16, MB_MSYSTEM);
|
||||||
|
error = md_get_mem(mdp, vcp->vc_ch, sblen, MB_MSYSTEM);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
vcp->vc_chlen = sblen;
|
||||||
|
vcp->obj.co_flags |= SMBV_ENCRYPT;
|
||||||
|
}
|
||||||
|
vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
|
||||||
|
if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
|
||||||
|
sp->sv_maxtx < 4096 &&
|
||||||
|
(sp->sv_caps & SMB_CAP_NT_SMBS) == 0) {
|
||||||
|
vcp->obj.co_flags |= SMBV_WIN95;
|
||||||
|
SMBSDEBUG("Win95 detected\n");
|
||||||
|
}
|
||||||
|
} else if (dp->d_id > SMB_DIALECT_CORE) {
|
||||||
|
md_get_uint16le(mdp, &tw);
|
||||||
|
sp->sv_sm = tw;
|
||||||
|
md_get_uint16le(mdp, &tw);
|
||||||
|
sp->sv_maxtx = tw;
|
||||||
|
md_get_uint16le(mdp, &sp->sv_maxmux);
|
||||||
|
md_get_uint16le(mdp, &sp->sv_maxvcs);
|
||||||
|
md_get_uint16le(mdp, &tw); /* rawmode */
|
||||||
|
md_get_uint32le(mdp, &sp->sv_skey);
|
||||||
|
if (wc == 13) { /* >= LANMAN1 */
|
||||||
|
md_get_uint16(mdp, &tw); /* time */
|
||||||
|
md_get_uint16(mdp, &tw1); /* date */
|
||||||
|
md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz);
|
||||||
|
md_get_uint16le(mdp, &swlen);
|
||||||
|
if (swlen > SMB_MAXCHALLENGELEN)
|
||||||
|
break;
|
||||||
|
md_get_uint16(mdp, NULL); /* mbz */
|
||||||
|
if (md_get_uint16(mdp, &bc) != 0)
|
||||||
|
break;
|
||||||
|
if (bc < swlen)
|
||||||
|
break;
|
||||||
|
if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
|
||||||
|
error = md_get_mem(mdp, vcp->vc_ch, swlen, MB_MSYSTEM);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
vcp->vc_chlen = swlen;
|
||||||
|
vcp->obj.co_flags |= SMBV_ENCRYPT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
|
||||||
|
} else { /* an old CORE protocol */
|
||||||
|
sp->sv_maxmux = 1;
|
||||||
|
}
|
||||||
|
error = 0;
|
||||||
|
} while (0);
|
||||||
|
if (error == 0) {
|
||||||
|
vcp->vc_maxvcs = sp->sv_maxvcs;
|
||||||
|
if (vcp->vc_maxvcs <= 1) {
|
||||||
|
if (vcp->vc_maxvcs == 0)
|
||||||
|
vcp->vc_maxvcs = 1;
|
||||||
|
}
|
||||||
|
if (sp->sv_maxtx <= 0 || sp->sv_maxtx > 0xffff)
|
||||||
|
sp->sv_maxtx = 1024;
|
||||||
|
SMB_TRAN_GETPARAM(vcp, SMBTP_SNDSZ, &maxqsz);
|
||||||
|
vcp->vc_txmax = min(sp->sv_maxtx, maxqsz);
|
||||||
|
SMBSDEBUG("TZ = %d\n", sp->sv_tz);
|
||||||
|
SMBSDEBUG("CAPS = %x\n", sp->sv_caps);
|
||||||
|
SMBSDEBUG("MAXMUX = %d\n", sp->sv_maxmux);
|
||||||
|
SMBSDEBUG("MAXVCS = %d\n", sp->sv_maxvcs);
|
||||||
|
SMBSDEBUG("MAXRAW = %d\n", sp->sv_maxraw);
|
||||||
|
SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx);
|
||||||
|
}
|
||||||
|
bad:
|
||||||
|
smb_rq_done(rqp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_rq *rqp;
|
||||||
|
struct mbchain *mbp;
|
||||||
|
/* u_int8_t wc;
|
||||||
|
u_int16_t tw, tw1;*/
|
||||||
|
smb_uniptr unipp, ntencpass = NULL;
|
||||||
|
char *pp, *up, *pbuf, *encpass;
|
||||||
|
int error, plen, uniplen, ulen;
|
||||||
|
|
||||||
|
vcp->vc_smbuid = SMB_UID_UNKNOWN;
|
||||||
|
|
||||||
|
if (smb_smb_nomux(vcp, scred, __FUNCTION__) != 0)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
|
||||||
|
encpass = malloc(24, M_SMBTEMP, M_WAITOK);
|
||||||
|
if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
|
||||||
|
iconv_convstr(vcp->vc_toupper, pbuf, smb_vc_getpass(vcp));
|
||||||
|
iconv_convstr(vcp->vc_toserver, pbuf, pbuf);
|
||||||
|
if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
|
||||||
|
uniplen = plen = 24;
|
||||||
|
smb_encrypt(pbuf, vcp->vc_ch, encpass);
|
||||||
|
ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
|
||||||
|
iconv_convstr(vcp->vc_toserver, pbuf, smb_vc_getpass(vcp));
|
||||||
|
smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass);
|
||||||
|
pp = encpass;
|
||||||
|
unipp = ntencpass;
|
||||||
|
} else {
|
||||||
|
plen = strlen(pbuf) + 1;
|
||||||
|
pp = pbuf;
|
||||||
|
uniplen = plen * 2;
|
||||||
|
ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
|
||||||
|
smb_strtouni(ntencpass, smb_vc_getpass(vcp));
|
||||||
|
plen--;
|
||||||
|
uniplen = 0/*-= 2*/;
|
||||||
|
unipp = ntencpass;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* In the share security mode password will be used
|
||||||
|
* only in the tree authentication
|
||||||
|
*/
|
||||||
|
pp = "";
|
||||||
|
plen = 1;
|
||||||
|
unipp = &smb_unieol;
|
||||||
|
uniplen = sizeof(smb_unieol);
|
||||||
|
}
|
||||||
|
smb_rq_wstart(rqp);
|
||||||
|
mbp = &rqp->sr_rq;
|
||||||
|
up = vcp->vc_username;
|
||||||
|
ulen = strlen(up) + 1;
|
||||||
|
mb_put_uint8(mbp, 0xff);
|
||||||
|
mb_put_uint8(mbp, 0);
|
||||||
|
mb_put_uint16le(mbp, 0);
|
||||||
|
mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx);
|
||||||
|
mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux);
|
||||||
|
mb_put_uint16le(mbp, vcp->vc_number);
|
||||||
|
mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey);
|
||||||
|
mb_put_uint16le(mbp, plen);
|
||||||
|
if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) {
|
||||||
|
mb_put_uint32le(mbp, 0);
|
||||||
|
smb_rq_wend(rqp);
|
||||||
|
smb_rq_bstart(rqp);
|
||||||
|
mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
|
||||||
|
smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);
|
||||||
|
} else {
|
||||||
|
mb_put_uint16le(mbp, uniplen);
|
||||||
|
mb_put_uint32le(mbp, 0); /* reserved */
|
||||||
|
mb_put_uint32le(mbp, 0); /* my caps */
|
||||||
|
smb_rq_wend(rqp);
|
||||||
|
smb_rq_bstart(rqp);
|
||||||
|
mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
|
||||||
|
mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM);
|
||||||
|
smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* AccountName */
|
||||||
|
smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE); /* PrimaryDomain */
|
||||||
|
smb_put_dstring(mbp, vcp, "FreeBSD", SMB_CS_NONE); /* Client's OS */
|
||||||
|
smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE); /* Client name */
|
||||||
|
}
|
||||||
|
smb_rq_bend(rqp);
|
||||||
|
if (ntencpass)
|
||||||
|
free(ntencpass, M_SMBTEMP);
|
||||||
|
error = smb_rq_simple(rqp);
|
||||||
|
SMBSDEBUG("%d\n", error);
|
||||||
|
if (error) {
|
||||||
|
if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess)
|
||||||
|
error = EAUTH;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
vcp->vc_smbuid = rqp->sr_rpuid;
|
||||||
|
bad:
|
||||||
|
free(encpass, M_SMBTEMP);
|
||||||
|
free(pbuf, M_SMBTEMP);
|
||||||
|
smb_rq_done(rqp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_rq *rqp;
|
||||||
|
struct mbchain *mbp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (smb_smb_nomux(vcp, scred, __FUNCTION__) != 0)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
mbp = &rqp->sr_rq;
|
||||||
|
smb_rq_wstart(rqp);
|
||||||
|
mb_put_uint8(mbp, 0xff);
|
||||||
|
mb_put_uint8(mbp, 0);
|
||||||
|
mb_put_uint16le(mbp, 0);
|
||||||
|
smb_rq_wend(rqp);
|
||||||
|
smb_rq_bstart(rqp);
|
||||||
|
smb_rq_bend(rqp);
|
||||||
|
error = smb_rq_simple(rqp);
|
||||||
|
SMBSDEBUG("%d\n", error);
|
||||||
|
smb_rq_done(rqp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char smb_any_share[] = "?????";
|
||||||
|
|
||||||
|
static char *
|
||||||
|
smb_share_typename(int stype)
|
||||||
|
{
|
||||||
|
char *pp;
|
||||||
|
|
||||||
|
switch (stype) {
|
||||||
|
case SMB_ST_DISK:
|
||||||
|
pp = "A:";
|
||||||
|
break;
|
||||||
|
case SMB_ST_PRINTER:
|
||||||
|
pp = smb_any_share; /* can't use LPT: here... */
|
||||||
|
break;
|
||||||
|
case SMB_ST_PIPE:
|
||||||
|
pp = "IPC";
|
||||||
|
break;
|
||||||
|
case SMB_ST_COMM:
|
||||||
|
pp = "COMM";
|
||||||
|
break;
|
||||||
|
case SMB_ST_ANY:
|
||||||
|
default:
|
||||||
|
pp = smb_any_share;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return pp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp;
|
||||||
|
struct smb_rq rq, *rqp = &rq;
|
||||||
|
struct mbchain *mbp;
|
||||||
|
char *pp, *pbuf, *encpass;
|
||||||
|
int error, plen, caseopt;
|
||||||
|
|
||||||
|
ssp->ss_tid = SMB_TID_UNKNOWN;
|
||||||
|
error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
vcp = rqp->sr_vc;
|
||||||
|
caseopt = SMB_CS_NONE;
|
||||||
|
if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
|
||||||
|
plen = 1;
|
||||||
|
pp = "";
|
||||||
|
pbuf = NULL;
|
||||||
|
encpass = NULL;
|
||||||
|
} else {
|
||||||
|
pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
|
||||||
|
encpass = malloc(24, M_SMBTEMP, M_WAITOK);
|
||||||
|
iconv_convstr(vcp->vc_toupper, pbuf, smb_share_getpass(ssp));
|
||||||
|
iconv_convstr(vcp->vc_toserver, pbuf, pbuf);
|
||||||
|
if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
|
||||||
|
plen = 24;
|
||||||
|
smb_encrypt(pbuf, vcp->vc_ch, encpass);
|
||||||
|
pp = encpass;
|
||||||
|
} else {
|
||||||
|
plen = strlen(pbuf) + 1;
|
||||||
|
pp = pbuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mbp = &rqp->sr_rq;
|
||||||
|
smb_rq_wstart(rqp);
|
||||||
|
mb_put_uint8(mbp, 0xff);
|
||||||
|
mb_put_uint8(mbp, 0);
|
||||||
|
mb_put_uint16le(mbp, 0);
|
||||||
|
mb_put_uint16le(mbp, 0); /* Flags */
|
||||||
|
mb_put_uint16le(mbp, plen);
|
||||||
|
smb_rq_wend(rqp);
|
||||||
|
smb_rq_bstart(rqp);
|
||||||
|
mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
|
||||||
|
smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt);
|
||||||
|
pp = vcp->vc_srvname;
|
||||||
|
smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt);
|
||||||
|
smb_put_dmem(mbp, vcp, "\\", 1, caseopt);
|
||||||
|
pp = ssp->ss_name;
|
||||||
|
smb_put_dstring(mbp, vcp, pp, caseopt);
|
||||||
|
pp = smb_share_typename(ssp->ss_type);
|
||||||
|
smb_put_dstring(mbp, vcp, pp, caseopt);
|
||||||
|
smb_rq_bend(rqp);
|
||||||
|
error = smb_rq_simple(rqp);
|
||||||
|
SMBSDEBUG("%d\n", error);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
ssp->ss_tid = rqp->sr_rptid;
|
||||||
|
ssp->ss_vcgenid = vcp->vc_genid;
|
||||||
|
ssp->ss_flags |= SMBS_CONNECTED;
|
||||||
|
bad:
|
||||||
|
if (encpass)
|
||||||
|
free(encpass, M_SMBTEMP);
|
||||||
|
if (pbuf)
|
||||||
|
free(pbuf, M_SMBTEMP);
|
||||||
|
smb_rq_done(rqp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_rq *rqp;
|
||||||
|
struct mbchain *mbp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (ssp->ss_tid == SMB_TID_UNKNOWN)
|
||||||
|
return 0;
|
||||||
|
error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
mbp = &rqp->sr_rq;
|
||||||
|
smb_rq_wstart(rqp);
|
||||||
|
smb_rq_wend(rqp);
|
||||||
|
smb_rq_bstart(rqp);
|
||||||
|
smb_rq_bend(rqp);
|
||||||
|
error = smb_rq_simple(rqp);
|
||||||
|
SMBSDEBUG("%d\n", error);
|
||||||
|
smb_rq_done(rqp);
|
||||||
|
ssp->ss_tid = SMB_TID_UNKNOWN;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline int
|
||||||
|
smb_smb_read(struct smb_share *ssp, u_int16_t fid,
|
||||||
|
int *len, int *rresid, struct uio *uio, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_rq *rqp;
|
||||||
|
struct mbchain *mbp;
|
||||||
|
struct mdchain *mdp;
|
||||||
|
u_int16_t resid, bc;
|
||||||
|
u_int8_t wc;
|
||||||
|
int error, rlen, blksz;
|
||||||
|
|
||||||
|
error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
|
||||||
|
rlen = *len = min(blksz, *len);
|
||||||
|
|
||||||
|
smb_rq_getrequest(rqp, &mbp);
|
||||||
|
smb_rq_wstart(rqp);
|
||||||
|
mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
|
||||||
|
mb_put_uint16le(mbp, rlen);
|
||||||
|
mb_put_uint32le(mbp, uio->uio_offset);
|
||||||
|
mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
|
||||||
|
smb_rq_wend(rqp);
|
||||||
|
smb_rq_bstart(rqp);
|
||||||
|
smb_rq_bend(rqp);
|
||||||
|
do {
|
||||||
|
error = smb_rq_simple(rqp);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
smb_rq_getreply(rqp, &mdp);
|
||||||
|
md_get_uint8(mdp, &wc);
|
||||||
|
if (wc != 5) {
|
||||||
|
error = EBADRPC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
md_get_uint16le(mdp, &resid);
|
||||||
|
md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
|
||||||
|
md_get_uint16le(mdp, &bc);
|
||||||
|
md_get_uint8(mdp, NULL); /* ignore buffer type */
|
||||||
|
md_get_uint16le(mdp, &resid);
|
||||||
|
if (resid == 0) {
|
||||||
|
*rresid = resid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
error = md_get_uio(mdp, uio, resid);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
*rresid = resid;
|
||||||
|
} while(0);
|
||||||
|
smb_rq_done(rqp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
|
||||||
|
struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
int tsize, len, resid;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
tsize = uio->uio_resid;
|
||||||
|
while (tsize > 0) {
|
||||||
|
len = tsize;
|
||||||
|
error = smb_smb_read(ssp, fid, &len, &resid, uio, scred);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
tsize -= resid;
|
||||||
|
if (resid < len)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline int
|
||||||
|
smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
|
||||||
|
struct uio *uio, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_rq *rqp;
|
||||||
|
struct mbchain *mbp;
|
||||||
|
struct mdchain *mdp;
|
||||||
|
u_int16_t resid;
|
||||||
|
u_int8_t wc;
|
||||||
|
int error, blksz;
|
||||||
|
|
||||||
|
blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
|
||||||
|
if (blksz > 0xffff)
|
||||||
|
blksz = 0xffff;
|
||||||
|
|
||||||
|
resid = *len = min(blksz, *len);
|
||||||
|
|
||||||
|
error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
smb_rq_getrequest(rqp, &mbp);
|
||||||
|
smb_rq_wstart(rqp);
|
||||||
|
mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
|
||||||
|
mb_put_uint16le(mbp, resid);
|
||||||
|
mb_put_uint32le(mbp, uio->uio_offset);
|
||||||
|
mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
|
||||||
|
smb_rq_wend(rqp);
|
||||||
|
smb_rq_bstart(rqp);
|
||||||
|
mb_put_uint8(mbp, SMB_DT_DATA);
|
||||||
|
mb_put_uint16le(mbp, resid);
|
||||||
|
do {
|
||||||
|
error = mb_put_uio(mbp, uio, resid);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
smb_rq_bend(rqp);
|
||||||
|
error = smb_rq_simple(rqp);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
smb_rq_getreply(rqp, &mdp);
|
||||||
|
md_get_uint8(mdp, &wc);
|
||||||
|
if (wc != 1) {
|
||||||
|
error = EBADRPC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
md_get_uint16le(mdp, &resid);
|
||||||
|
*rresid = resid;
|
||||||
|
} while(0);
|
||||||
|
smb_rq_done(rqp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
|
||||||
|
struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
int error = 0, len, tsize, resid;
|
||||||
|
struct uio olduio;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* review: manage iov more precisely
|
||||||
|
*/
|
||||||
|
if (uio->uio_iovcnt != 1) {
|
||||||
|
SMBERROR("can't handle iovcnt > 1\n");
|
||||||
|
return EIO;
|
||||||
|
}
|
||||||
|
tsize = uio->uio_resid;
|
||||||
|
olduio = *uio;
|
||||||
|
while (tsize > 0) {
|
||||||
|
len = tsize;
|
||||||
|
error = smb_smb_write(ssp, fid, &len, &resid, uio, scred);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
if (resid < len) {
|
||||||
|
error = EIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tsize -= resid;
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
*uio = olduio;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_rq *rqp;
|
||||||
|
struct mbchain *mbp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
mbp = &rqp->sr_rq;
|
||||||
|
smb_rq_wstart(rqp);
|
||||||
|
mb_put_uint16le(mbp, 1);
|
||||||
|
smb_rq_wend(rqp);
|
||||||
|
smb_rq_bstart(rqp);
|
||||||
|
mb_put_uint32le(mbp, 0);
|
||||||
|
smb_rq_bend(rqp);
|
||||||
|
error = smb_rq_simple(rqp);
|
||||||
|
SMBSDEBUG("%d\n", error);
|
||||||
|
smb_rq_done(rqp);
|
||||||
|
return error;
|
||||||
|
}
|
359
sys/netsmb/smb_subr.c
Normal file
359
sys/netsmb/smb_subr.c
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001 Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/lock.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/signalvar.h>
|
||||||
|
#include <sys/mbuf.h>
|
||||||
|
|
||||||
|
#include <sys/iconv.h>
|
||||||
|
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_rq.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
|
||||||
|
MALLOC_DEFINE(M_SMBDATA, "SMBDATA", "Misc netsmb data");
|
||||||
|
MALLOC_DEFINE(M_SMBSTR, "SMBSTR", "netsmb string data");
|
||||||
|
MALLOC_DEFINE(M_SMBTEMP, "SMBTEMP", "Temp netsmb data");
|
||||||
|
|
||||||
|
smb_unichar smb_unieol = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_makescred(struct smb_cred *scred, struct proc *p, struct ucred *cred)
|
||||||
|
{
|
||||||
|
if (p) {
|
||||||
|
scred->scr_p = p;
|
||||||
|
scred->scr_cred = cred ? cred : p->p_ucred;
|
||||||
|
} else {
|
||||||
|
scred->scr_p = NULL;
|
||||||
|
scred->scr_cred = cred ? cred : NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_proc_intr(struct proc *p)
|
||||||
|
{
|
||||||
|
#if __FreeBSD_version < 400009
|
||||||
|
|
||||||
|
if (p && p->p_siglist &&
|
||||||
|
(((p->p_siglist & ~p->p_sigmask) & ~p->p_sigignore) & SMB_SIGMASK))
|
||||||
|
return EINTR;
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
sigset_t tmpset;
|
||||||
|
|
||||||
|
if (p == NULL)
|
||||||
|
return 0;
|
||||||
|
tmpset = p->p_siglist;
|
||||||
|
SIGSETNAND(tmpset, p->p_sigmask);
|
||||||
|
SIGSETNAND(tmpset, p->p_sigignore);
|
||||||
|
if (SIGNOTEMPTY(p->p_siglist) && SMB_SIGMASK(tmpset))
|
||||||
|
return EINTR;
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
smb_strdup(const char *s)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = s ? strlen(s) + 1 : 1;
|
||||||
|
p = malloc(len, M_SMBSTR, M_WAITOK);
|
||||||
|
if (s)
|
||||||
|
bcopy(s, p, len);
|
||||||
|
else
|
||||||
|
*p = 0;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* duplicate string from a user space.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
smb_strdupin(char *s, int maxlen)
|
||||||
|
{
|
||||||
|
char *p, bt;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
for (p = s; ;p++) {
|
||||||
|
if (copyin(p, &bt, 1))
|
||||||
|
return NULL;
|
||||||
|
len++;
|
||||||
|
if (maxlen && len > maxlen)
|
||||||
|
return NULL;
|
||||||
|
if (bt == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p = malloc(len, M_SMBSTR, M_WAITOK);
|
||||||
|
copyin(s, p, len);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* duplicate memory block from a user space.
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
smb_memdupin(void *umem, int len)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (len > 8 * 1024)
|
||||||
|
return NULL;
|
||||||
|
p = malloc(len, M_SMBSTR, M_WAITOK);
|
||||||
|
if (copyin(umem, p, len) == 0)
|
||||||
|
return p;
|
||||||
|
free(p, M_SMBSTR);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* duplicate memory block in the kernel space.
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
smb_memdup(const void *umem, int len)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (len > 8 * 1024)
|
||||||
|
return NULL;
|
||||||
|
p = malloc(len, M_SMBSTR, M_WAITOK);
|
||||||
|
if (p == NULL)
|
||||||
|
return NULL;
|
||||||
|
bcopy(umem, p, len);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_strfree(char *s)
|
||||||
|
{
|
||||||
|
free(s, M_SMBSTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_memfree(void *s)
|
||||||
|
{
|
||||||
|
free(s, M_SMBSTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
smb_zmalloc(unsigned long size, struct malloc_type *type, int flags)
|
||||||
|
{
|
||||||
|
|
||||||
|
return malloc(size, type, flags | M_ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb_strtouni(u_int16_t *dst, const char *src)
|
||||||
|
{
|
||||||
|
while (*src) {
|
||||||
|
*dst++ = htoles(*src++);
|
||||||
|
}
|
||||||
|
*dst = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SMB_SOCKETDATA_DEBUG
|
||||||
|
void
|
||||||
|
m_dumpm(struct mbuf *m) {
|
||||||
|
char *p;
|
||||||
|
int len;
|
||||||
|
printf("d=");
|
||||||
|
while(m) {
|
||||||
|
p=mtod(m,char *);
|
||||||
|
len=m->m_len;
|
||||||
|
printf("(%d)",len);
|
||||||
|
while(len--){
|
||||||
|
printf("%02x ",((int)*(p++)) & 0xff);
|
||||||
|
}
|
||||||
|
m=m->m_next;
|
||||||
|
};
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_maperror(int eclass, int eno)
|
||||||
|
{
|
||||||
|
if (eclass == 0 && eno == 0)
|
||||||
|
return 0;
|
||||||
|
switch (eclass) {
|
||||||
|
case ERRDOS:
|
||||||
|
switch (eno) {
|
||||||
|
case ERRbadfunc:
|
||||||
|
case ERRbadmcb:
|
||||||
|
case ERRbadenv:
|
||||||
|
case ERRbadformat:
|
||||||
|
case ERRrmuns:
|
||||||
|
return EINVAL;
|
||||||
|
case ERRbadfile:
|
||||||
|
case ERRbadpath:
|
||||||
|
case ERRremcd:
|
||||||
|
case 66: /* nt returns it when share not available */
|
||||||
|
return ENOENT;
|
||||||
|
case ERRnofids:
|
||||||
|
return EMFILE;
|
||||||
|
case ERRnoaccess:
|
||||||
|
case ERRbadshare:
|
||||||
|
return EACCES;
|
||||||
|
case ERRbadfid:
|
||||||
|
return EBADF;
|
||||||
|
case ERRnomem:
|
||||||
|
return ENOMEM; /* actually remote no mem... */
|
||||||
|
case ERRbadmem:
|
||||||
|
return EFAULT;
|
||||||
|
case ERRbadaccess:
|
||||||
|
return EACCES;
|
||||||
|
case ERRbaddata:
|
||||||
|
return E2BIG;
|
||||||
|
case ERRbaddrive:
|
||||||
|
case ERRnotready: /* nt */
|
||||||
|
return ENXIO;
|
||||||
|
case ERRdiffdevice:
|
||||||
|
return EXDEV;
|
||||||
|
case ERRnofiles:
|
||||||
|
return 0; /* eeof ? */
|
||||||
|
return ETXTBSY;
|
||||||
|
case ERRlock:
|
||||||
|
return EDEADLK;
|
||||||
|
case ERRfilexists:
|
||||||
|
return EEXIST;
|
||||||
|
case 123: /* dunno what is it, but samba maps as noent */
|
||||||
|
return ENOENT;
|
||||||
|
case 145: /* samba */
|
||||||
|
return ENOTEMPTY;
|
||||||
|
case 183:
|
||||||
|
return EEXIST;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ERRSRV:
|
||||||
|
switch (eno) {
|
||||||
|
case ERRerror:
|
||||||
|
return EINVAL;
|
||||||
|
case ERRbadpw:
|
||||||
|
return EAUTH;
|
||||||
|
case ERRaccess:
|
||||||
|
return EACCES;
|
||||||
|
case ERRinvnid:
|
||||||
|
return ENETRESET;
|
||||||
|
case ERRinvnetname:
|
||||||
|
SMBERROR("NetBIOS name is invalid\n");
|
||||||
|
return EAUTH;
|
||||||
|
case 3: /* reserved and returned */
|
||||||
|
return EIO;
|
||||||
|
case 2239: /* NT: account exists but disabled */
|
||||||
|
return EPERM;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ERRHRD:
|
||||||
|
switch (eno) {
|
||||||
|
case ERRnowrite:
|
||||||
|
return EROFS;
|
||||||
|
case ERRbadunit:
|
||||||
|
return ENODEV;
|
||||||
|
case ERRnotready:
|
||||||
|
case ERRbadcmd:
|
||||||
|
case ERRdata:
|
||||||
|
return EIO;
|
||||||
|
case ERRbadreq:
|
||||||
|
return EBADRPC;
|
||||||
|
case ERRbadshare:
|
||||||
|
return ETXTBSY;
|
||||||
|
case ERRlock:
|
||||||
|
return EDEADLK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SMBERROR("Unmapped error %d:%d\n", eclass, eno);
|
||||||
|
return EBADRPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_copy_iconv(struct mbchain *mbp, c_caddr_t src, caddr_t dst, int len)
|
||||||
|
{
|
||||||
|
int outlen = len;
|
||||||
|
|
||||||
|
return iconv_conv((struct iconv_drv*)mbp->mb_udata, &src, &len, &dst, &outlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
|
||||||
|
int size, int caseopt)
|
||||||
|
{
|
||||||
|
struct iconv_drv *dp = vcp->vc_toserver;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return 0;
|
||||||
|
if (dp == NULL) {
|
||||||
|
return mb_put_mem(mbp, src, size, MB_MSYSTEM);
|
||||||
|
}
|
||||||
|
mbp->mb_copy = smb_copy_iconv;
|
||||||
|
mbp->mb_udata = dp;
|
||||||
|
return mb_put_mem(mbp, src, size, MB_MCUSTOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
|
||||||
|
int caseopt)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
return mb_put_uint8(mbp, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_put_asunistring(struct smb_rq *rqp, const char *src)
|
||||||
|
{
|
||||||
|
struct mbchain *mbp = &rqp->sr_rq;
|
||||||
|
struct iconv_drv *dp = rqp->sr_vc->vc_toserver;
|
||||||
|
u_char c;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
while (*src) {
|
||||||
|
iconv_convmem(dp, &c, src++, 1);
|
||||||
|
error = mb_put_uint16le(mbp, c);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return mb_put_uint16le(mbp, 0);
|
||||||
|
}
|
198
sys/netsmb/smb_subr.h
Normal file
198
sys/netsmb/smb_subr.h
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001, Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#ifndef _NETSMB_SMB_SUBR_H_
|
||||||
|
#define _NETSMB_SMB_SUBR_H_
|
||||||
|
|
||||||
|
#ifndef _KERNEL
|
||||||
|
#error "This file shouldn't be included from userland programs"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MALLOC_DECLARE
|
||||||
|
MALLOC_DECLARE(M_SMBTEMP);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __FreeBSD_version > 500000
|
||||||
|
#define FB_CURRENT
|
||||||
|
#else
|
||||||
|
# if __FreeBSD_version > 400000
|
||||||
|
# define FB_RELENG4
|
||||||
|
# else
|
||||||
|
# error "Unsupported version of FreeBSD"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SMBERROR(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
|
||||||
|
#define SMBPANIC(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
|
||||||
|
|
||||||
|
#ifdef SMB_SOCKET_DEBUG
|
||||||
|
#define SMBSDEBUG(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
|
||||||
|
#else
|
||||||
|
#define SMBSDEBUG(format, args...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SMB_IOD_DEBUG
|
||||||
|
#define SMBIODEBUG(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
|
||||||
|
#else
|
||||||
|
#define SMBIODEBUG(format, args...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SMB_SOCKETDATA_DEBUG
|
||||||
|
void m_dumpm(struct mbuf *m);
|
||||||
|
#else
|
||||||
|
#define m_dumpm(m)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __FreeBSD_version > 400009
|
||||||
|
#define SMB_SIGMASK(set) \
|
||||||
|
(SIGISMEMBER(set, SIGINT) || SIGISMEMBER(set, SIGTERM) || \
|
||||||
|
SIGISMEMBER(set, SIGHUP) || SIGISMEMBER(set, SIGKILL) || \
|
||||||
|
SIGISMEMBER(set, SIGQUIT))
|
||||||
|
|
||||||
|
#define smb_suser(cred) suser_xxx(cred, NULL, 0)
|
||||||
|
#else
|
||||||
|
#define SMB_SIGMASK (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGKILL)| \
|
||||||
|
sigmask(SIGHUP)|sigmask(SIGQUIT))
|
||||||
|
|
||||||
|
#define smb_suser(cred) suser((cred), NULL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compatibility wrappers for simple locks
|
||||||
|
*/
|
||||||
|
#if __FreeBSD_version < 500000
|
||||||
|
|
||||||
|
#include <sys/lock.h>
|
||||||
|
|
||||||
|
#define lockdestroy(lock)
|
||||||
|
#define smb_slock simplelock
|
||||||
|
#define smb_sl_init(mtx, desc) simple_lock_init(mtx)
|
||||||
|
#define smb_sl_destroy(mtx)
|
||||||
|
#define smb_sl_lock(mtx) simple_lock(mtx)
|
||||||
|
#define smb_sl_unlock(mtx) simple_unlock(mtx)
|
||||||
|
/*
|
||||||
|
#define mtx lock
|
||||||
|
#define mtx_init(mtx, desc, flags) lockinit(mtx, PWAIT, desc, 0, 0)
|
||||||
|
#define mtx_lock(mtx) lockmgr(mtx, LK_EXCLUSIVE, NULL, curproc)
|
||||||
|
#define mtx_unlock(mtx) lockmgr(mtx, LK_RELEASE, NULL, curproc)
|
||||||
|
#define mtx_destroy(mtx)
|
||||||
|
*/
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <sys/mutex.h>
|
||||||
|
|
||||||
|
#define smb_slock mtx
|
||||||
|
#define smb_sl_init(mtx, desc) mtx_init(mtx, desc, MTX_DEF)
|
||||||
|
#define smb_sl_destroy(mtx) mtx_destroy(mtx)
|
||||||
|
#define smb_sl_lock(mtx) mtx_lock(mtx)
|
||||||
|
#define smb_sl_unlock(mtx) mtx_unlock(mtx)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SMB_STRFREE(p) do { if (p) smb_strfree(p); } while(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The simple try/catch/finally interface.
|
||||||
|
* With GCC it is possible to allow more than one try/finally block per
|
||||||
|
* function, but we'll avoid it to maintain portability.
|
||||||
|
*/
|
||||||
|
#define itry { \
|
||||||
|
__label__ _finlab, _catchlab; \
|
||||||
|
int _tval; \
|
||||||
|
|
||||||
|
#define icatch(var) \
|
||||||
|
goto _finlab; \
|
||||||
|
(void)&&_catchlab; \
|
||||||
|
_catchlab: \
|
||||||
|
var = _tval;
|
||||||
|
|
||||||
|
#define ifinally (void)&&_finlab; \
|
||||||
|
_finlab:
|
||||||
|
#define iendtry }
|
||||||
|
|
||||||
|
#define inocatch \
|
||||||
|
goto _finlab; \
|
||||||
|
(void)&&_catchlab; \
|
||||||
|
_catchlab: \
|
||||||
|
|
||||||
|
#define ithrow(t) do { \
|
||||||
|
if ((_tval = (int)(t)) != 0) \
|
||||||
|
goto _catchlab; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ierror(t,e) do { \
|
||||||
|
if (t) { \
|
||||||
|
_tval = e; \
|
||||||
|
goto _catchlab; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
typedef u_int16_t smb_unichar;
|
||||||
|
typedef smb_unichar *smb_uniptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Crediantials of user/process being processing in the connection procedures
|
||||||
|
*/
|
||||||
|
struct smb_cred {
|
||||||
|
struct proc * scr_p;
|
||||||
|
struct ucred * scr_cred;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern smb_unichar smb_unieol;
|
||||||
|
|
||||||
|
struct mbchain;
|
||||||
|
struct smb_vc;
|
||||||
|
struct smb_rq;
|
||||||
|
|
||||||
|
void smb_makescred(struct smb_cred *scred, struct proc *p, struct ucred *cred);
|
||||||
|
int smb_proc_intr(struct proc *);
|
||||||
|
char *smb_strdup(const char *s);
|
||||||
|
void *smb_memdup(const void *umem, int len);
|
||||||
|
char *smb_strdupin(char *s, int maxlen);
|
||||||
|
void *smb_memdupin(void *umem, int len);
|
||||||
|
void smb_strtouni(u_int16_t *dst, const char *src);
|
||||||
|
void smb_strfree(char *s);
|
||||||
|
void smb_memfree(void *s);
|
||||||
|
void *smb_zmalloc(unsigned long size, struct malloc_type *type, int flags);
|
||||||
|
|
||||||
|
int smb_encrypt(const u_char *apwd, u_char *C8, u_char *RN);
|
||||||
|
int smb_ntencrypt(const u_char *apwd, u_char *C8, u_char *RN);
|
||||||
|
int smb_maperror(int eclass, int eno);
|
||||||
|
int smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp,
|
||||||
|
const char *src, int len, int caseopt);
|
||||||
|
int smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp,
|
||||||
|
const char *src, int caseopt);
|
||||||
|
int smb_put_string(struct smb_rq *rqp, const char *src);
|
||||||
|
int smb_put_asunistring(struct smb_rq *rqp, const char *src);
|
||||||
|
|
||||||
|
#endif /* !_NETSMB_SMB_SUBR_H_ */
|
89
sys/netsmb/smb_tran.h
Normal file
89
sys/netsmb/smb_tran.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001, Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _NETSMB_SMB_TRAN_H_
|
||||||
|
#define _NETSMB_SMB_TRAN_H_
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Known transports
|
||||||
|
*/
|
||||||
|
#define SMBT_NBTCP 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transport parameters
|
||||||
|
*/
|
||||||
|
#define SMBTP_SNDSZ 1 /* R - int */
|
||||||
|
#define SMBTP_RCVSZ 2 /* R - int */
|
||||||
|
#define SMBTP_TIMEOUT 3 /* RW - struct timespec */
|
||||||
|
#define SMBTP_SELECTID 4 /* RW - (void *) */
|
||||||
|
|
||||||
|
struct smb_tran_ops;
|
||||||
|
|
||||||
|
struct smb_tran_desc {
|
||||||
|
sa_family_t tr_type;
|
||||||
|
int (*tr_create)(struct smb_vc *vcp, struct proc *p);
|
||||||
|
int (*tr_done)(struct smb_vc *vcp, struct proc *p);
|
||||||
|
int (*tr_bind)(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p);
|
||||||
|
int (*tr_connect)(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p);
|
||||||
|
int (*tr_disconnect)(struct smb_vc *vcp, struct proc *p);
|
||||||
|
int (*tr_send)(struct smb_vc *vcp, struct mbuf *m0, struct proc *p);
|
||||||
|
int (*tr_recv)(struct smb_vc *vcp, struct mbuf **mpp, struct proc *p);
|
||||||
|
void (*tr_timo)(struct smb_vc *vcp);
|
||||||
|
void (*tr_intr)(struct smb_vc *vcp);
|
||||||
|
int (*tr_getparam)(struct smb_vc *vcp, int param, void *data);
|
||||||
|
int (*tr_setparam)(struct smb_vc *vcp, int param, void *data);
|
||||||
|
int (*tr_fatal)(struct smb_vc *vcp, int error);
|
||||||
|
#ifdef notyet
|
||||||
|
int (*tr_poll)(struct smb_vc *vcp, struct proc *p);
|
||||||
|
int (*tr_cmpaddr)(void *addr1, void *addr2);
|
||||||
|
#endif
|
||||||
|
LIST_ENTRY(smb_tran_desc) tr_link;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SMB_TRAN_CREATE(vcp,p) (vcp)->vc_tdesc->tr_create(vcp,p)
|
||||||
|
#define SMB_TRAN_DONE(vcp,p) (vcp)->vc_tdesc->tr_done(vcp,p)
|
||||||
|
#define SMB_TRAN_BIND(vcp,sap,p) (vcp)->vc_tdesc->tr_bind(vcp,sap,p)
|
||||||
|
#define SMB_TRAN_CONNECT(vcp,sap,p) (vcp)->vc_tdesc->tr_connect(vcp,sap,p)
|
||||||
|
#define SMB_TRAN_DISCONNECT(vcp,p) (vcp)->vc_tdesc->tr_disconnect(vcp,p)
|
||||||
|
#define SMB_TRAN_SEND(vcp,m0,p) (vcp)->vc_tdesc->tr_send(vcp,m0,p)
|
||||||
|
#define SMB_TRAN_RECV(vcp,m,p) (vcp)->vc_tdesc->tr_recv(vcp,m,p)
|
||||||
|
#define SMB_TRAN_TIMO(vcp) (vcp)->vc_tdesc->tr_timo(vcp)
|
||||||
|
#define SMB_TRAN_INTR(vcp) (vcp)->vc_tdesc->tr_intr(vcp)
|
||||||
|
#define SMB_TRAN_GETPARAM(vcp,par,data) (vcp)->vc_tdesc->tr_getparam(vcp, par, data)
|
||||||
|
#define SMB_TRAN_SETPARAM(vcp,par,data) (vcp)->vc_tdesc->tr_setparam(vcp, par, data)
|
||||||
|
#define SMB_TRAN_FATAL(vcp, error) (vcp)->vc_tdesc->tr_fatal(vcp, error)
|
||||||
|
|
||||||
|
#endif /* _NETSMB_SMB_TRAN_H_ */
|
672
sys/netsmb/smb_trantcp.c
Normal file
672
sys/netsmb/smb_trantcp.c
Normal file
@ -0,0 +1,672 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001 Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/mbuf.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/protosw.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/socketvar.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/route.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
|
||||||
|
#include <sys/mchain.h>
|
||||||
|
|
||||||
|
#include <netsmb/netbios.h>
|
||||||
|
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_tran.h>
|
||||||
|
#include <netsmb/smb_trantcp.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
|
||||||
|
#define M_NBDATA M_PCB
|
||||||
|
|
||||||
|
static int smb_tcpsndbuf = 10 * 1024;
|
||||||
|
static int smb_tcprcvbuf = 10 * 1024;
|
||||||
|
|
||||||
|
SYSCTL_DECL(_net_smb);
|
||||||
|
SYSCTL_INT(_net_smb, OID_AUTO, tcpsndbuf, CTLFLAG_RW, &smb_tcpsndbuf, 0, "");
|
||||||
|
SYSCTL_INT(_net_smb, OID_AUTO, tcprcvbuf, CTLFLAG_RW, &smb_tcprcvbuf, 0, "");
|
||||||
|
|
||||||
|
#define nb_sosend(so,m,flags,p) (so)->so_proto->pr_usrreqs->pru_sosend( \
|
||||||
|
so, NULL, 0, m, 0, flags, p)
|
||||||
|
|
||||||
|
static int nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp,
|
||||||
|
u_int8_t *rpcodep, struct proc *p);
|
||||||
|
static int smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p);
|
||||||
|
|
||||||
|
static int
|
||||||
|
nb_setsockopt_int(struct socket *so, int level, int name, int val)
|
||||||
|
{
|
||||||
|
struct sockopt sopt;
|
||||||
|
|
||||||
|
bzero(&sopt, sizeof(sopt));
|
||||||
|
sopt.sopt_level = level;
|
||||||
|
sopt.sopt_name = name;
|
||||||
|
sopt.sopt_val = &val;
|
||||||
|
sopt.sopt_valsize = sizeof(val);
|
||||||
|
return sosetopt(so, &sopt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline int
|
||||||
|
nb_poll(struct nbpcb *nbp, int events, struct proc *p)
|
||||||
|
{
|
||||||
|
return nbp->nbp_tso->so_proto->pr_usrreqs->pru_sopoll(nbp->nbp_tso,
|
||||||
|
events, NULL, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nbssn_rselect(struct nbpcb *nbp, struct timeval *tv, int events, struct proc *p)
|
||||||
|
{
|
||||||
|
struct timeval atv, rtv, ttv;
|
||||||
|
int s, timo, error;
|
||||||
|
|
||||||
|
if (tv) {
|
||||||
|
atv = *tv;
|
||||||
|
if (itimerfix(&atv)) {
|
||||||
|
error = EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
getmicrouptime(&rtv);
|
||||||
|
timevaladd(&atv, &rtv);
|
||||||
|
}
|
||||||
|
timo = 0;
|
||||||
|
retry:
|
||||||
|
p->p_flag |= P_SELECT;
|
||||||
|
error = nb_poll(nbp, events, p);
|
||||||
|
if (error) {
|
||||||
|
error = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (tv) {
|
||||||
|
getmicrouptime(&rtv);
|
||||||
|
if (timevalcmp(&rtv, &atv, >=))
|
||||||
|
goto done;
|
||||||
|
ttv = atv;
|
||||||
|
timevalsub(&ttv, &rtv);
|
||||||
|
timo = tvtohz(&ttv);
|
||||||
|
}
|
||||||
|
s = splhigh();
|
||||||
|
if ((p->p_flag & P_SELECT) == 0) {
|
||||||
|
splx(s);
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
p->p_flag &= ~P_SELECT;
|
||||||
|
error = tsleep((caddr_t)&selwait, PSOCK, "nbsel", timo);
|
||||||
|
splx(s);
|
||||||
|
done:
|
||||||
|
p->p_flag &= ~P_SELECT;
|
||||||
|
if (error == ERESTART)
|
||||||
|
return 0;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nb_intr(struct nbpcb *nbp, struct proc *p)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nb_upcall(struct socket *so, void *arg, int waitflag)
|
||||||
|
{
|
||||||
|
struct nbpcb *nbp = arg;
|
||||||
|
|
||||||
|
if (arg == NULL || nbp->nbp_selectid == NULL)
|
||||||
|
return;
|
||||||
|
wakeup(nbp->nbp_selectid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nb_sethdr(struct mbuf *m, u_int8_t type, u_int32_t len)
|
||||||
|
{
|
||||||
|
u_int32_t *p = mtod(m, u_int32_t *);
|
||||||
|
|
||||||
|
*p = htonl((len & 0x1FFFF) | (type << 24));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
u_char seglen, *cp;
|
||||||
|
|
||||||
|
cp = snb->snb_name;
|
||||||
|
if (*cp == 0)
|
||||||
|
return EINVAL;
|
||||||
|
NBDEBUG("[%s]\n", cp);
|
||||||
|
for (;;) {
|
||||||
|
seglen = (*cp) + 1;
|
||||||
|
error = mb_put_mem(mbp, cp, seglen, MB_MSYSTEM);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
if (seglen == 1)
|
||||||
|
break;
|
||||||
|
cp += seglen;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct proc *p)
|
||||||
|
{
|
||||||
|
struct socket *so;
|
||||||
|
int error, s;
|
||||||
|
|
||||||
|
error = socreate(AF_INET, &so, SOCK_STREAM, IPPROTO_TCP, p);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
nbp->nbp_tso = so;
|
||||||
|
so->so_upcallarg = (caddr_t)nbp;
|
||||||
|
so->so_upcall = nb_upcall;
|
||||||
|
so->so_rcv.sb_flags |= SB_UPCALL;
|
||||||
|
so->so_rcv.sb_timeo = (5 * hz);
|
||||||
|
so->so_snd.sb_timeo = (5 * hz);
|
||||||
|
error = soreserve(so, nbp->nbp_sndbuf, nbp->nbp_rcvbuf);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
nb_setsockopt_int(so, SOL_SOCKET, SO_KEEPALIVE, 1);
|
||||||
|
nb_setsockopt_int(so, IPPROTO_TCP, TCP_NODELAY, 1);
|
||||||
|
so->so_rcv.sb_flags &= ~SB_NOINTR;
|
||||||
|
so->so_snd.sb_flags &= ~SB_NOINTR;
|
||||||
|
error = soconnect(so, (struct sockaddr*)to, p);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
s = splnet();
|
||||||
|
while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
|
||||||
|
tsleep(&so->so_timeo, PSOCK, "nbcon", 2 * hz);
|
||||||
|
if ((so->so_state & SS_ISCONNECTING) && so->so_error == 0 &&
|
||||||
|
(error = nb_intr(nbp, p)) != 0) {
|
||||||
|
so->so_state &= ~SS_ISCONNECTING;
|
||||||
|
splx(s);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (so->so_error) {
|
||||||
|
error = so->so_error;
|
||||||
|
so->so_error = 0;
|
||||||
|
splx(s);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
splx(s);
|
||||||
|
return 0;
|
||||||
|
bad:
|
||||||
|
smb_nbst_disconnect(nbp->nbp_vc, p);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nbssn_rq_request(struct nbpcb *nbp, struct proc *p)
|
||||||
|
{
|
||||||
|
struct mbchain mb, *mbp = &mb;
|
||||||
|
struct mdchain md, *mdp = &md;
|
||||||
|
struct mbuf *m0;
|
||||||
|
struct timeval tv;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
u_short port;
|
||||||
|
u_int8_t rpcode;
|
||||||
|
int error, rplen;
|
||||||
|
|
||||||
|
error = mb_init(mbp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
mb_put_uint32le(mbp, 0);
|
||||||
|
nb_put_name(mbp, nbp->nbp_paddr);
|
||||||
|
nb_put_name(mbp, nbp->nbp_laddr);
|
||||||
|
nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4);
|
||||||
|
error = nb_sosend(nbp->nbp_tso, mbp->mb_top, 0, p);
|
||||||
|
if (!error) {
|
||||||
|
nbp->nbp_state = NBST_RQSENT;
|
||||||
|
}
|
||||||
|
mb_detach(mbp);
|
||||||
|
mb_done(mbp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
TIMESPEC_TO_TIMEVAL(&tv, &nbp->nbp_timo);
|
||||||
|
error = nbssn_rselect(nbp, &tv, POLLIN, p);
|
||||||
|
if (error == EWOULDBLOCK) { /* Timeout */
|
||||||
|
NBDEBUG("initial request timeout\n");
|
||||||
|
return ETIMEDOUT;
|
||||||
|
}
|
||||||
|
if (error) /* restart or interrupt */
|
||||||
|
return error;
|
||||||
|
error = nbssn_recv(nbp, &m0, &rplen, &rpcode, p);
|
||||||
|
if (error) {
|
||||||
|
NBDEBUG("recv() error %d\n", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Process NETBIOS reply
|
||||||
|
*/
|
||||||
|
if (m0)
|
||||||
|
md_initm(mdp, m0);
|
||||||
|
error = 0;
|
||||||
|
do {
|
||||||
|
if (rpcode == NB_SSN_POSRESP) {
|
||||||
|
nbp->nbp_state = NBST_SESSION;
|
||||||
|
nbp->nbp_flags |= NBF_CONNECTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rpcode != NB_SSN_RTGRESP) {
|
||||||
|
error = ECONNABORTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rplen != 6) {
|
||||||
|
error = ECONNABORTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM);
|
||||||
|
md_get_uint16(mdp, &port);
|
||||||
|
sin.sin_port = port;
|
||||||
|
nbp->nbp_state = NBST_RETARGET;
|
||||||
|
smb_nbst_disconnect(nbp->nbp_vc, p);
|
||||||
|
error = nb_connect_in(nbp, &sin, p);
|
||||||
|
if (!error)
|
||||||
|
error = nbssn_rq_request(nbp, p);
|
||||||
|
if (error) {
|
||||||
|
smb_nbst_disconnect(nbp->nbp_vc, p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(0);
|
||||||
|
if (m0)
|
||||||
|
md_done(mdp);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nbssn_recvhdr(struct nbpcb *nbp, int *lenp,
|
||||||
|
u_int8_t *rpcodep, int flags, struct proc *p)
|
||||||
|
{
|
||||||
|
struct socket *so = nbp->nbp_tso;
|
||||||
|
struct uio auio;
|
||||||
|
struct iovec aio;
|
||||||
|
u_int32_t len;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
aio.iov_base = (caddr_t)&len;
|
||||||
|
aio.iov_len = sizeof(len);
|
||||||
|
auio.uio_iov = &aio;
|
||||||
|
auio.uio_iovcnt = 1;
|
||||||
|
auio.uio_segflg = UIO_SYSSPACE;
|
||||||
|
auio.uio_rw = UIO_READ;
|
||||||
|
auio.uio_offset = 0;
|
||||||
|
auio.uio_resid = sizeof(len);
|
||||||
|
auio.uio_procp = p;
|
||||||
|
error = so->so_proto->pr_usrreqs->pru_soreceive
|
||||||
|
(so, (struct sockaddr **)NULL, &auio,
|
||||||
|
(struct mbuf **)NULL, (struct mbuf **)NULL, &flags);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
if (auio.uio_resid > 0) {
|
||||||
|
SMBSDEBUG("short reply\n");
|
||||||
|
return EPIPE;
|
||||||
|
}
|
||||||
|
len = ntohl(len);
|
||||||
|
*rpcodep = (len >> 24) & 0xFF;
|
||||||
|
len &= 0x1ffff;
|
||||||
|
if (len > SMB_MAXPKTLEN) {
|
||||||
|
SMBERROR("packet too long (%d)\n", len);
|
||||||
|
return EFBIG;
|
||||||
|
}
|
||||||
|
*lenp = len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp,
|
||||||
|
u_int8_t *rpcodep, struct proc *p)
|
||||||
|
{
|
||||||
|
struct socket *so = nbp->nbp_tso;
|
||||||
|
struct uio auio;
|
||||||
|
struct mbuf *m;
|
||||||
|
u_int8_t rpcode;
|
||||||
|
int len;
|
||||||
|
int error, rcvflg;
|
||||||
|
|
||||||
|
if (so == NULL)
|
||||||
|
return ENOTCONN;
|
||||||
|
|
||||||
|
if (mpp)
|
||||||
|
*mpp = NULL;
|
||||||
|
for(;;) {
|
||||||
|
m = NULL;
|
||||||
|
error = nbssn_recvhdr(nbp, &len, &rpcode, MSG_DONTWAIT, p);
|
||||||
|
if (so->so_state &
|
||||||
|
(SS_ISDISCONNECTING | SS_ISDISCONNECTED | SS_CANTRCVMORE)) {
|
||||||
|
nbp->nbp_state = NBST_CLOSED;
|
||||||
|
NBDEBUG("session closed by peer\n");
|
||||||
|
return ECONNRESET;
|
||||||
|
}
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
if (len == 0 && nbp->nbp_state != NBST_SESSION)
|
||||||
|
break;
|
||||||
|
if (rpcode == NB_SSN_KEEPALIVE)
|
||||||
|
continue;
|
||||||
|
bzero(&auio, sizeof(auio));
|
||||||
|
auio.uio_resid = len;
|
||||||
|
auio.uio_procp = p;
|
||||||
|
do {
|
||||||
|
rcvflg = MSG_WAITALL;
|
||||||
|
error = so->so_proto->pr_usrreqs->pru_soreceive
|
||||||
|
(so, (struct sockaddr **)NULL,
|
||||||
|
&auio, &m, (struct mbuf **)NULL, &rcvflg);
|
||||||
|
} while (error == EWOULDBLOCK || error == EINTR ||
|
||||||
|
error == ERESTART);
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
if (auio.uio_resid > 0) {
|
||||||
|
SMBERROR("packet is shorter than expected\n");
|
||||||
|
error = EPIPE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nbp->nbp_state == NBST_SESSION &&
|
||||||
|
rpcode == NB_SSN_MESSAGE)
|
||||||
|
break;
|
||||||
|
NBDEBUG("non-session packet %x\n", rpcode);
|
||||||
|
if (m)
|
||||||
|
m_freem(m);
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
if (m)
|
||||||
|
m_freem(m);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if (mpp)
|
||||||
|
*mpp = m;
|
||||||
|
else
|
||||||
|
m_freem(m);
|
||||||
|
*lenp = len;
|
||||||
|
*rpcodep = rpcode;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SMB transport interface
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
smb_nbst_create(struct smb_vc *vcp, struct proc *p)
|
||||||
|
{
|
||||||
|
struct nbpcb *nbp;
|
||||||
|
|
||||||
|
MALLOC(nbp, struct nbpcb *, sizeof *nbp, M_NBDATA, M_WAITOK);
|
||||||
|
bzero(nbp, sizeof *nbp);
|
||||||
|
nbp->nbp_timo.tv_sec = 15; /* XXX: sysctl ? */
|
||||||
|
nbp->nbp_state = NBST_CLOSED;
|
||||||
|
nbp->nbp_vc = vcp;
|
||||||
|
nbp->nbp_sndbuf = smb_tcpsndbuf;
|
||||||
|
nbp->nbp_rcvbuf = smb_tcprcvbuf;
|
||||||
|
vcp->vc_tdata = nbp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_nbst_done(struct smb_vc *vcp, struct proc *p)
|
||||||
|
{
|
||||||
|
struct nbpcb *nbp = vcp->vc_tdata;
|
||||||
|
|
||||||
|
if (nbp == NULL)
|
||||||
|
return ENOTCONN;
|
||||||
|
smb_nbst_disconnect(vcp, p);
|
||||||
|
if (nbp->nbp_laddr)
|
||||||
|
free(nbp->nbp_laddr, M_SONAME);
|
||||||
|
if (nbp->nbp_paddr)
|
||||||
|
free(nbp->nbp_paddr, M_SONAME);
|
||||||
|
free(nbp, M_NBDATA);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
|
||||||
|
{
|
||||||
|
struct nbpcb *nbp = vcp->vc_tdata;
|
||||||
|
struct sockaddr_nb *snb;
|
||||||
|
int error, slen;
|
||||||
|
|
||||||
|
NBDEBUG("\n");
|
||||||
|
error = EINVAL;
|
||||||
|
do {
|
||||||
|
if (nbp->nbp_flags & NBF_LOCADDR)
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* It is possible to create NETBIOS name in the kernel,
|
||||||
|
* but nothing prevents us to do it in the user space.
|
||||||
|
*/
|
||||||
|
if (sap == NULL)
|
||||||
|
break;
|
||||||
|
slen = sap->sa_len;
|
||||||
|
if (slen < NB_MINSALEN)
|
||||||
|
break;
|
||||||
|
snb = (struct sockaddr_nb*)dup_sockaddr(sap, 1);
|
||||||
|
if (snb == NULL) {
|
||||||
|
error = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nbp->nbp_laddr = snb;
|
||||||
|
nbp->nbp_flags |= NBF_LOCADDR;
|
||||||
|
error = 0;
|
||||||
|
} while(0);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
|
||||||
|
{
|
||||||
|
struct nbpcb *nbp = vcp->vc_tdata;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
struct sockaddr_nb *snb;
|
||||||
|
struct timespec ts1, ts2;
|
||||||
|
int error, slen;
|
||||||
|
|
||||||
|
NBDEBUG("\n");
|
||||||
|
if (nbp->nbp_tso != NULL)
|
||||||
|
return EISCONN;
|
||||||
|
if (nbp->nbp_laddr == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
slen = sap->sa_len;
|
||||||
|
if (slen < NB_MINSALEN)
|
||||||
|
return EINVAL;
|
||||||
|
if (nbp->nbp_paddr) {
|
||||||
|
free(nbp->nbp_paddr, M_SONAME);
|
||||||
|
nbp->nbp_paddr = NULL;
|
||||||
|
}
|
||||||
|
snb = (struct sockaddr_nb*)dup_sockaddr(sap, 1);
|
||||||
|
if (snb == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
nbp->nbp_paddr = snb;
|
||||||
|
sin = snb->snb_addrin;
|
||||||
|
getnanotime(&ts1);
|
||||||
|
error = nb_connect_in(nbp, &sin, p);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
getnanotime(&ts2);
|
||||||
|
timespecsub(&ts2, &ts1);
|
||||||
|
if (ts2.tv_sec == 0 && ts2.tv_sec == 0)
|
||||||
|
ts2.tv_sec = 1;
|
||||||
|
nbp->nbp_timo = ts2;
|
||||||
|
timespecadd(&nbp->nbp_timo, &ts2);
|
||||||
|
timespecadd(&nbp->nbp_timo, &ts2);
|
||||||
|
timespecadd(&nbp->nbp_timo, &ts2); /* * 4 */
|
||||||
|
error = nbssn_rq_request(nbp, p);
|
||||||
|
if (error)
|
||||||
|
smb_nbst_disconnect(vcp, p);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p)
|
||||||
|
{
|
||||||
|
struct nbpcb *nbp = vcp->vc_tdata;
|
||||||
|
struct socket *so;
|
||||||
|
|
||||||
|
if (nbp == NULL || nbp->nbp_tso == NULL)
|
||||||
|
return ENOTCONN;
|
||||||
|
if ((so = nbp->nbp_tso) != NULL) {
|
||||||
|
nbp->nbp_flags &= ~NBF_CONNECTED;
|
||||||
|
nbp->nbp_tso = (struct socket *)NULL;
|
||||||
|
soshutdown(so, 2);
|
||||||
|
soclose(so);
|
||||||
|
}
|
||||||
|
if (nbp->nbp_state != NBST_RETARGET) {
|
||||||
|
nbp->nbp_state = NBST_CLOSED;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_nbst_send(struct smb_vc *vcp, struct mbuf *m0, struct proc *p)
|
||||||
|
{
|
||||||
|
struct nbpcb *nbp = vcp->vc_tdata;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (nbp->nbp_state != NBST_SESSION) {
|
||||||
|
error = ENOTCONN;
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
M_PREPEND(m0, 4, M_WAITOK);
|
||||||
|
if (m0 == NULL)
|
||||||
|
return ENOBUFS;
|
||||||
|
nb_sethdr(m0, NB_SSN_MESSAGE, m_fixhdr(m0) - 4);
|
||||||
|
error = nb_sosend(nbp->nbp_tso, m0, 0, p);
|
||||||
|
return error;
|
||||||
|
abort:
|
||||||
|
if (m0)
|
||||||
|
m_freem(m0);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_nbst_recv(struct smb_vc *vcp, struct mbuf **mpp, struct proc *p)
|
||||||
|
{
|
||||||
|
struct nbpcb *nbp = vcp->vc_tdata;
|
||||||
|
u_int8_t rpcode;
|
||||||
|
int error, rplen;
|
||||||
|
|
||||||
|
nbp->nbp_flags |= NBF_RECVLOCK;
|
||||||
|
error = nbssn_recv(nbp, mpp, &rplen, &rpcode, p);
|
||||||
|
nbp->nbp_flags &= ~NBF_RECVLOCK;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_nbst_timo(struct smb_vc *vcp)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_nbst_intr(struct smb_vc *vcp)
|
||||||
|
{
|
||||||
|
struct nbpcb *nbp = vcp->vc_tdata;
|
||||||
|
|
||||||
|
if (nbp == NULL || nbp->nbp_tso == NULL)
|
||||||
|
return;
|
||||||
|
sorwakeup(nbp->nbp_tso);
|
||||||
|
sowwakeup(nbp->nbp_tso);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
|
||||||
|
{
|
||||||
|
struct nbpcb *nbp = vcp->vc_tdata;
|
||||||
|
|
||||||
|
switch (param) {
|
||||||
|
case SMBTP_SNDSZ:
|
||||||
|
*(int*)data = nbp->nbp_sndbuf;
|
||||||
|
break;
|
||||||
|
case SMBTP_RCVSZ:
|
||||||
|
*(int*)data = nbp->nbp_rcvbuf;
|
||||||
|
break;
|
||||||
|
case SMBTP_TIMEOUT:
|
||||||
|
*(struct timespec*)data = nbp->nbp_timo;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
|
||||||
|
{
|
||||||
|
struct nbpcb *nbp = vcp->vc_tdata;
|
||||||
|
|
||||||
|
switch (param) {
|
||||||
|
case SMBTP_SELECTID:
|
||||||
|
nbp->nbp_selectid = data;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for fatal errors
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
smb_nbst_fatal(struct smb_vc *vcp, int error)
|
||||||
|
{
|
||||||
|
switch (error) {
|
||||||
|
case ENOTCONN:
|
||||||
|
case ENETRESET:
|
||||||
|
case ECONNABORTED:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct smb_tran_desc smb_tran_nbtcp_desc = {
|
||||||
|
SMBT_NBTCP,
|
||||||
|
smb_nbst_create, smb_nbst_done,
|
||||||
|
smb_nbst_bind, smb_nbst_connect, smb_nbst_disconnect,
|
||||||
|
smb_nbst_send, smb_nbst_recv,
|
||||||
|
smb_nbst_timo, smb_nbst_intr,
|
||||||
|
smb_nbst_getparam, smb_nbst_setparam,
|
||||||
|
smb_nbst_fatal
|
||||||
|
};
|
||||||
|
|
88
sys/netsmb/smb_trantcp.h
Normal file
88
sys/netsmb/smb_trantcp.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001, Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#ifndef _NETSMB_SMB_TRANTCP_H_
|
||||||
|
#define _NETSMB_SMB_TRANTCP_H_
|
||||||
|
|
||||||
|
#ifdef _KERNEL
|
||||||
|
|
||||||
|
#ifdef NB_DEBUG
|
||||||
|
#define NBDEBUG(format, args...) printf("%s(%d): "format, \
|
||||||
|
__FUNCTION__ , __LINE__ ,## args)
|
||||||
|
#else
|
||||||
|
#define NBDEBUG(format, args...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum nbstate {
|
||||||
|
NBST_CLOSED,
|
||||||
|
NBST_RQSENT,
|
||||||
|
NBST_SESSION,
|
||||||
|
NBST_RETARGET,
|
||||||
|
NBST_REFUSED
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* socket specific data
|
||||||
|
*/
|
||||||
|
struct nbpcb {
|
||||||
|
struct smb_vc * nbp_vc;
|
||||||
|
struct socket * nbp_tso; /* transport socket */
|
||||||
|
struct sockaddr_nb *nbp_laddr; /* local address */
|
||||||
|
struct sockaddr_nb *nbp_paddr; /* peer address */
|
||||||
|
|
||||||
|
int nbp_flags;
|
||||||
|
#define NBF_LOCADDR 0x0001 /* has local addr */
|
||||||
|
#define NBF_CONNECTED 0x0002
|
||||||
|
#define NBF_RECVLOCK 0x0004
|
||||||
|
|
||||||
|
enum nbstate nbp_state;
|
||||||
|
struct timespec nbp_timo;
|
||||||
|
int nbp_sndbuf;
|
||||||
|
int nbp_rcvbuf;
|
||||||
|
void * nbp_selectid;
|
||||||
|
|
||||||
|
/* LIST_ENTRY(nbpcb) nbp_link;*/
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Nominal space allocated per a NETBIOS socket.
|
||||||
|
*/
|
||||||
|
#define NB_SNDQ (10 * 1024)
|
||||||
|
#define NB_RCVQ (20 * 1024)
|
||||||
|
|
||||||
|
extern struct smb_tran_desc smb_tran_nbtcp_desc;
|
||||||
|
|
||||||
|
#endif /* _KERNEL */
|
||||||
|
|
||||||
|
#endif /* !_NETSMB_SMB_TRANTCP_H_ */
|
355
sys/netsmb/smb_usr.c
Normal file
355
sys/netsmb/smb_usr.c
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2001 Boris Popov
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by Boris Popov.
|
||||||
|
* 4. Neither the name of the author nor the names of any co-contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/conf.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/socketvar.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
|
#include <sys/iconv.h>
|
||||||
|
|
||||||
|
#include <netsmb/smb.h>
|
||||||
|
#include <netsmb/smb_conn.h>
|
||||||
|
#include <netsmb/smb_rq.h>
|
||||||
|
#include <netsmb/smb_subr.h>
|
||||||
|
#include <netsmb/smb_dev.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* helpers for nsmb device. Can be moved to the smb_dev.c file.
|
||||||
|
*/
|
||||||
|
static void smb_usr_vcspec_free(struct smb_vcspec *spec);
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_usr_vc2spec(struct smbioc_ossn *dp, struct smb_vcspec *spec)
|
||||||
|
{
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
bzero(spec, sizeof(*spec));
|
||||||
|
if (dp->ioc_user[0] == 0)
|
||||||
|
return EINVAL;
|
||||||
|
if (dp->ioc_server == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
if (dp->ioc_localcs[0] == 0) {
|
||||||
|
SMBERROR("no local charset ?\n");
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
spec->sap = smb_memdupin(dp->ioc_server, dp->ioc_svlen);
|
||||||
|
if (spec->sap == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
if (dp->ioc_local) {
|
||||||
|
spec->lap = smb_memdupin(dp->ioc_local, dp->ioc_lolen);
|
||||||
|
if (spec->lap == NULL) {
|
||||||
|
smb_usr_vcspec_free(spec);
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spec->srvname = dp->ioc_srvname;
|
||||||
|
spec->pass = dp->ioc_password;
|
||||||
|
spec->domain = dp->ioc_workgroup;
|
||||||
|
spec->username = dp->ioc_user;
|
||||||
|
spec->mode = dp->ioc_mode;
|
||||||
|
spec->rights = dp->ioc_rights;
|
||||||
|
spec->owner = dp->ioc_owner;
|
||||||
|
spec->group = dp->ioc_group;
|
||||||
|
spec->localcs = dp->ioc_localcs;
|
||||||
|
spec->servercs = dp->ioc_servercs;
|
||||||
|
if (dp->ioc_opt & SMBVOPT_PRIVATE)
|
||||||
|
flags |= SMBV_PRIVATE;
|
||||||
|
if (dp->ioc_opt & SMBVOPT_SINGLESHARE)
|
||||||
|
flags |= SMBV_PRIVATE | SMBV_SINGLESHARE;
|
||||||
|
spec->flags = flags;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
smb_usr_vcspec_free(struct smb_vcspec *spec)
|
||||||
|
{
|
||||||
|
if (spec->sap)
|
||||||
|
smb_memfree(spec->sap);
|
||||||
|
if (spec->lap)
|
||||||
|
smb_memfree(spec->lap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_usr_share2spec(struct smbioc_oshare *dp, struct smb_sharespec *spec)
|
||||||
|
{
|
||||||
|
bzero(spec, sizeof(*spec));
|
||||||
|
spec->mode = dp->ioc_mode;
|
||||||
|
spec->rights = dp->ioc_rights;
|
||||||
|
spec->owner = dp->ioc_owner;
|
||||||
|
spec->group = dp->ioc_group;
|
||||||
|
spec->name = dp->ioc_share;
|
||||||
|
spec->stype = dp->ioc_stype;
|
||||||
|
spec->pass = dp->ioc_password;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_usr_lookup(struct smbioc_lookup *dp, struct smb_cred *scred,
|
||||||
|
struct smb_vc **vcpp, struct smb_share **sspp)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = NULL;
|
||||||
|
struct smb_vcspec vspec;
|
||||||
|
struct smb_sharespec sspec, *sspecp = NULL;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
|
||||||
|
return EINVAL;
|
||||||
|
error = smb_usr_vc2spec(&dp->ioc_ssn, &vspec);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
if (dp->ioc_flags & SMBLK_CREATE)
|
||||||
|
vspec.flags |= SMBV_CREATE;
|
||||||
|
|
||||||
|
if (dp->ioc_level >= SMBL_SHARE) {
|
||||||
|
error = smb_usr_share2spec(&dp->ioc_sh, &sspec);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
sspecp = &sspec;
|
||||||
|
}
|
||||||
|
error = smb_sm_lookup(&vspec, sspecp, scred, &vcp);
|
||||||
|
if (error == 0) {
|
||||||
|
*vcpp = vcp;
|
||||||
|
*sspp = vspec.ssp;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
smb_usr_vcspec_free(&vspec);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Connect to the resource specified by smbioc_ossn structure.
|
||||||
|
* It may either find an existing connection or try to establish a new one.
|
||||||
|
* If no errors occured smb_vc returned locked and referenced.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smb_usr_opensession(struct smbioc_ossn *dp, struct smb_cred *scred,
|
||||||
|
struct smb_vc **vcpp)
|
||||||
|
{
|
||||||
|
struct smb_vc *vcp = NULL;
|
||||||
|
struct smb_vcspec vspec;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = smb_usr_vc2spec(dp, &vspec);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
if (dp->ioc_opt & SMBVOPT_CREATE)
|
||||||
|
vspec.flags |= SMBV_CREATE;
|
||||||
|
|
||||||
|
error = smb_sm_lookup(&vspec, NULL, scred, &vcp);
|
||||||
|
smb_usr_vcspec_free(&vspec);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_usr_openshare(struct smb_vc *vcp, struct smbioc_oshare *dp,
|
||||||
|
struct smb_cred *scred, struct smb_share **sspp)
|
||||||
|
{
|
||||||
|
struct smb_share *ssp;
|
||||||
|
struct smb_sharespec shspec;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = smb_usr_share2spec(dp, &shspec);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
error = smb_vc_lookupshare(vcp, &shspec, scred, &ssp);
|
||||||
|
if (error == 0) {
|
||||||
|
*sspp = ssp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ((dp->ioc_opt & SMBSOPT_CREATE) == 0)
|
||||||
|
return error;
|
||||||
|
error = smb_share_create(vcp, &shspec, scred, &ssp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
error = smb_smb_treeconnect(ssp, scred);
|
||||||
|
if (error) {
|
||||||
|
smb_share_put(ssp, scred);
|
||||||
|
} else
|
||||||
|
*sspp = ssp;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp,
|
||||||
|
struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_rq rq, *rqp = &rq;
|
||||||
|
struct mbchain *mbp;
|
||||||
|
struct mdchain *mdp;
|
||||||
|
u_int8_t wc;
|
||||||
|
u_int16_t bc;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
switch (dp->ioc_cmd) {
|
||||||
|
case SMB_COM_TRANSACTION2:
|
||||||
|
case SMB_COM_TRANSACTION2_SECONDARY:
|
||||||
|
case SMB_COM_CLOSE_AND_TREE_DISC:
|
||||||
|
case SMB_COM_TREE_CONNECT:
|
||||||
|
case SMB_COM_TREE_DISCONNECT:
|
||||||
|
case SMB_COM_NEGOTIATE:
|
||||||
|
case SMB_COM_SESSION_SETUP_ANDX:
|
||||||
|
case SMB_COM_LOGOFF_ANDX:
|
||||||
|
case SMB_COM_TREE_CONNECT_ANDX:
|
||||||
|
return EPERM;
|
||||||
|
}
|
||||||
|
error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
mbp = &rqp->sr_rq;
|
||||||
|
smb_rq_wstart(rqp);
|
||||||
|
error = mb_put_mem(mbp, dp->ioc_twords, dp->ioc_twc * 2, MB_MUSER);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
smb_rq_wend(rqp);
|
||||||
|
smb_rq_bstart(rqp);
|
||||||
|
error = mb_put_mem(mbp, dp->ioc_tbytes, dp->ioc_tbc, MB_MUSER);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
smb_rq_bend(rqp);
|
||||||
|
error = smb_rq_simple(rqp);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
mdp = &rqp->sr_rp;
|
||||||
|
md_get_uint8(mdp, &wc);
|
||||||
|
dp->ioc_rwc = wc;
|
||||||
|
wc *= 2;
|
||||||
|
if (wc > dp->ioc_rpbufsz) {
|
||||||
|
error = EBADRPC;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
error = md_get_mem(mdp, dp->ioc_rpbuf, wc, MB_MUSER);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
md_get_uint16le(mdp, &bc);
|
||||||
|
if ((wc + bc) > dp->ioc_rpbufsz) {
|
||||||
|
error = EBADRPC;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
dp->ioc_rbc = bc;
|
||||||
|
error = md_get_mem(mdp, dp->ioc_rpbuf + wc, bc, MB_MUSER);
|
||||||
|
bad:
|
||||||
|
dp->ioc_errclass = rqp->sr_errclass;
|
||||||
|
dp->ioc_serror = rqp->sr_serror;
|
||||||
|
dp->ioc_error = rqp->sr_error;
|
||||||
|
smb_rq_done(rqp);
|
||||||
|
return error;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb_cpdatain(struct mbchain *mbp, int len, caddr_t data)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
error = mb_init(mbp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
return mb_put_mem(mbp, data, len, MB_MUSER);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *dp,
|
||||||
|
struct smb_cred *scred)
|
||||||
|
{
|
||||||
|
struct smb_t2rq t2, *t2p = &t2;
|
||||||
|
struct mdchain *mdp;
|
||||||
|
int error, len;
|
||||||
|
|
||||||
|
if (dp->ioc_tparamcnt > 0xffff || dp->ioc_tdatacnt > 0xffff ||
|
||||||
|
dp->ioc_setupcnt > 3)
|
||||||
|
return EINVAL;
|
||||||
|
error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup[0], scred);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
len = t2p->t2_setupcount = dp->ioc_setupcnt;
|
||||||
|
if (len > 1)
|
||||||
|
t2p->t2_setupdata = dp->ioc_setup;
|
||||||
|
if (dp->ioc_name) {
|
||||||
|
t2p->t_name = smb_strdupin(dp->ioc_name, 128);
|
||||||
|
if (t2p->t_name == NULL) {
|
||||||
|
error = ENOMEM;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t2p->t2_maxscount = 0;
|
||||||
|
t2p->t2_maxpcount = dp->ioc_rparamcnt;
|
||||||
|
t2p->t2_maxdcount = dp->ioc_rdatacnt;
|
||||||
|
error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt, dp->ioc_tparam);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
error = smb_cpdatain(&t2p->t2_tdata, dp->ioc_tdatacnt, dp->ioc_tdata);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
error = smb_t2_request(t2p);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
mdp = &t2p->t2_rparam;
|
||||||
|
if (mdp->md_top) {
|
||||||
|
len = m_fixhdr(mdp->md_top);
|
||||||
|
if (len > dp->ioc_rparamcnt) {
|
||||||
|
error = EMSGSIZE;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
dp->ioc_rparamcnt = len;
|
||||||
|
error = md_get_mem(mdp, dp->ioc_rparam, len, MB_MUSER);
|
||||||
|
if (error)
|
||||||
|
goto bad;
|
||||||
|
} else
|
||||||
|
dp->ioc_rparamcnt = 0;
|
||||||
|
mdp = &t2p->t2_rdata;
|
||||||
|
if (mdp->md_top) {
|
||||||
|
len = m_fixhdr(mdp->md_top);
|
||||||
|
if (len > dp->ioc_rdatacnt) {
|
||||||
|
error = EMSGSIZE;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
dp->ioc_rdatacnt = len;
|
||||||
|
error = md_get_mem(mdp, dp->ioc_rdata, len, MB_MUSER);
|
||||||
|
} else
|
||||||
|
dp->ioc_rdatacnt = 0;
|
||||||
|
bad:
|
||||||
|
if (t2p->t_name)
|
||||||
|
smb_strfree(t2p->t_name);
|
||||||
|
smb_t2_done(t2p);
|
||||||
|
return error;
|
||||||
|
}
|
47
sys/sys/md4.h
Normal file
47
sys/sys/md4.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/* MD4.H - header file for MD4C.C
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||||
|
rights reserved.
|
||||||
|
|
||||||
|
License to copy and use this software is granted provided that it
|
||||||
|
is identified as the "RSA Data Security, Inc. MD4 Message-Digest
|
||||||
|
Algorithm" in all material mentioning or referencing this software
|
||||||
|
or this function.
|
||||||
|
License is also granted to make and use derivative works provided
|
||||||
|
that such works are identified as "derived from the RSA Data
|
||||||
|
Security, Inc. MD4 Message-Digest Algorithm" in all material
|
||||||
|
mentioning or referencing the derived work.
|
||||||
|
|
||||||
|
RSA Data Security, Inc. makes no representations concerning either
|
||||||
|
the merchantability of this software or the suitability of this
|
||||||
|
software for any particular purpose. It is provided "as is"
|
||||||
|
without express or implied warranty of any kind.
|
||||||
|
|
||||||
|
These notices must be retained in any copies of any part of this
|
||||||
|
documentation and/or software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MD4_H_
|
||||||
|
#define _MD4_H_
|
||||||
|
/* MD4 context. */
|
||||||
|
typedef struct MD4Context {
|
||||||
|
u_int32_t state[4]; /* state (ABCD) */
|
||||||
|
u_int32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||||
|
unsigned char buffer[64]; /* input buffer */
|
||||||
|
} MD4_CTX;
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
void MD4Init(MD4_CTX *);
|
||||||
|
void MD4Update(MD4_CTX *, const unsigned char *, unsigned int);
|
||||||
|
void MD4Pad(MD4_CTX *);
|
||||||
|
void MD4Final(unsigned char [16], MD4_CTX *);
|
||||||
|
char * MD4End(MD4_CTX *, char *);
|
||||||
|
char * MD4File(const char *, char *);
|
||||||
|
char * MD4Data(const unsigned char *, unsigned int, char *);
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif /* _MD4_H_ */
|
Loading…
Reference in New Issue
Block a user