diff --git a/sys/fs/smbfs/smbfs_vfsops.c b/sys/fs/smbfs/smbfs_vfsops.c index 2d8b3ac47180..5bc646a2a0d8 100644 --- a/sys/fs/smbfs/smbfs_vfsops.c +++ b/sys/fs/smbfs/smbfs_vfsops.c @@ -1,396 +1,397 @@ /* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int smbfs_debuglevel = 0; static int smbfs_version = SMBFS_VERSION; #ifdef SMBFS_USEZONE #include #include vm_zone_t smbfsmount_zone; #endif SYSCTL_NODE(_vfs, OID_AUTO, smbfs, CTLFLAG_RW, 0, "SMB/CIFS filesystem"); 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 vfs_init_t smbfs_init; static vfs_uninit_t smbfs_uninit; static vfs_mount_t smbfs_mount; static vfs_start_t smbfs_start; static vfs_root_t smbfs_root; static vfs_quotactl_t smbfs_quotactl; static vfs_statfs_t smbfs_statfs; static vfs_unmount_t smbfs_unmount; static struct vfsops smbfs_vfsops = { .vfs_init = smbfs_init, .vfs_mount = smbfs_mount, .vfs_quotactl = smbfs_quotactl, .vfs_root = smbfs_root, .vfs_start = smbfs_start, .vfs_statfs = smbfs_statfs, .vfs_sync = vfs_stdsync, .vfs_uninit = smbfs_uninit, .vfs_unmount = smbfs_unmount, }; VFS_SET(smbfs_vfsops, smbfs, VFCF_NETWORK); MODULE_DEPEND(smbfs, netsmb, NSMB_VERSION, NSMB_VERSION, NSMB_VERSION); MODULE_DEPEND(smbfs, libiconv, 1, 1, 1); MODULE_DEPEND(smbfs, libmchain, 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 thread *td) { 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; 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, td, td->td_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, td); 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_WAITOK|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);*/ 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, td); SMBVDEBUG("root.v_usecount = %d\n", vrefcnt(vp)); #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 thread *td) { struct smbmount *smp = VFSTOSMBFS(mp); struct smb_cred scred; int error, flags; SMBVDEBUG("smbfs_unmount: flags=%04x\n", mntflags); flags = 0; if (mntflags & MNT_FORCE) flags |= FORCECLOSE; /* * Keep trying to flush the vnode list for the mount while * some are still busy and we are making progress towards * making them not busy. This is needed because smbfs vnodes * reference their parent directory but may appear after their * parent in the list; one pass over the vnode list is not * sufficient in this case. */ do { smp->sm_didrele = 0; /* There is 1 extra root vnode reference from smbfs_mount(). */ error = vflush(mp, 1, flags); } while (error == EBUSY && smp->sm_didrele != 0); if (error) return error; smb_makescred(&scred, td, td->td_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 thread *td = curthread; struct ucred *cred = td->td_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, td); } smb_makescred(&scred, td, 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; ASSERT_VOP_LOCKED(vp, "smbfs_root"); vp->v_vflag |= VV_ROOT; np = VTOSMB(vp); smp->sm_root = np; *vpp = vp; return 0; } /* * Vfs start routine, a no-op. */ /* ARGSUSED */ static int smbfs_start(mp, flags, td) struct mount *mp; int flags; struct thread *td; { SMBVDEBUG("flags=%04x\n", flags); return 0; } /* * Do operations associated with quotas, not supported */ /* ARGSUSED */ static int smbfs_quotactl(mp, cmd, uid, arg, td) struct mount *mp; int cmd; uid_t uid; caddr_t arg; struct thread *td; { SMBVDEBUG("return EOPNOTSUPP\n"); return EOPNOTSUPP; } /*ARGSUSED*/ int smbfs_init(struct vfsconf *vfsp) { #ifndef SMP int name[2]; - int olen, ncpu, plen, error; + int ncpu, error; + size_t olen, plen; name[0] = CTL_HW; name[1] = HW_NCPU; error = kernel_sysctl(curthread, 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 thread *td) { 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, td, td->td_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; /* filesystem 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; } diff --git a/sys/netncp/ncp_ncp.c b/sys/netncp/ncp_ncp.c index e7b5e16e0d48..bf51b438480a 100644 --- a/sys/netncp/ncp_ncp.c +++ b/sys/netncp/ncp_ncp.c @@ -1,508 +1,509 @@ /* * Copyright (c) 1999, 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. * * Core of NCP protocol */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef NCP_DATA_DEBUG static 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 /* NCP_DATA_DEBUG */ int ncp_chkintr(struct ncp_conn *conn, struct thread *td) { struct proc *p; sigset_t tmpset; if (td == NULL) return 0; p = td->td_proc; PROC_LOCK(p); tmpset = p->p_siglist; SIGSETOR(tmpset, td->td_siglist); SIGSETNAND(tmpset, td->td_sigmask); mtx_lock(&p->p_sigacts->ps_mtx); SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore); mtx_unlock(&p->p_sigacts->ps_mtx); if (SIGNOTEMPTY(td->td_siglist) && NCP_SIGMASK(tmpset)) { PROC_UNLOCK(p); return EINTR; } PROC_UNLOCK(p); return 0; } /* * Process initial NCP handshake (attach) * NOTE: Since all functions below may change conn attributes, they * should be called with LOCKED connection, also they use procp & ucred */ int ncp_ncp_connect(struct ncp_conn *conn) { struct ncp_rq *rqp; struct ncp_rphdr *rp; int error; error = ncp_rq_alloc_any(NCP_ALLOC_SLOT, 0, conn, conn->td, conn->ucred, &rqp); if (error) return error; conn->flags &= ~(NCPFL_SIGNACTIVE | NCPFL_SIGNWANTED | NCPFL_ATTACHED | NCPFL_LOGGED | NCPFL_INVALID); conn->seq = 0; error = ncp_request_int(rqp); if (!error) { rp = mtod(rqp->rp.md_top, struct ncp_rphdr*); conn->connid = rp->conn_low + (rp->conn_high << 8); } ncp_rq_done(rqp); if (error) return error; conn->flags |= NCPFL_ATTACHED | NCPFL_WASATTACHED; return 0; } int ncp_ncp_disconnect(struct ncp_conn *conn) { struct ncp_rq *rqp; int error; NCPSDEBUG("for connid=%d\n",conn->nc_id); #ifdef NCPBURST ncp_burst_disconnect(conn); #endif if (conn->flags & NCPFL_ATTACHED) { error = ncp_rq_alloc_any(NCP_FREE_SLOT, 0, conn, conn->td, conn->ucred, &rqp); if (!error) { ncp_request_int(rqp); ncp_rq_done(rqp); } } ncp_conn_invalidate(conn); ncp_sock_disconnect(conn); return 0; } /* * All negotiation functions expect a locked connection */ int ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target) { struct ncp_rq *rqp; u_int16_t bsize; int error; error = ncp_rq_alloc(0x21, conn, conn->td, conn->ucred, &rqp); if (error) return error; mb_put_uint16be(&rqp->rq, size); error = ncp_request(rqp); if (error) return error; md_get_uint16be(&rqp->rp, &bsize); *target = min(bsize, size); ncp_rq_done(rqp); return error; } static int ncp_negotiate_size_and_options(struct ncp_conn *conn, int size, int options, int *ret_size, u_int8_t *ret_options) { struct ncp_rq *rqp; u_int16_t rs; int error; error = ncp_rq_alloc(0x61, conn, conn->td, conn->ucred, &rqp); if (error) return error; mb_put_uint16be(&rqp->rq, size); mb_put_uint8(&rqp->rq, options); rqp->nr_minrplen = 2 + 2 + 1; error = ncp_request(rqp); if (error) return error; md_get_uint16be(&rqp->rp, &rs); *ret_size = (rs == 0) ? size : min(rs, size); md_get_uint16be(&rqp->rp, &rs); /* skip echo socket */ md_get_uint8(&rqp->rp, ret_options); ncp_rq_done(rqp); return error; } int ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, u_int8_t in_options) { u_int8_t options; - int neg_buffsize, error, sl, ckslevel, ilen; + int neg_buffsize, error, sl, ckslevel; + size_t ilen; sl = conn->li.sig_level; if (sl >= 2) in_options |= NCP_SECURITY_LEVEL_SIGN_HEADERS; if (conn->li.saddr.sa_family == AF_IPX) { ilen = sizeof(ckslevel); error = kernel_sysctlbyname(curthread, "net.ipx.ipx.checksum", &ckslevel, &ilen, NULL, 0, NULL); if (error) return error; if (ckslevel == 2) in_options |= NCP_IPX_CHECKSUM; } error = ncp_negotiate_size_and_options(conn, buffsize, in_options, &neg_buffsize, &options); if (!error) { if (conn->li.saddr.sa_family == AF_IPX && ((options ^ in_options) & NCP_IPX_CHECKSUM)) { if (ckslevel == 2) { printf("Server refuses to support IPX checksums\n"); return NWE_REQUESTER_FAILURE; } in_options |= NCP_IPX_CHECKSUM; error = 1; } if ((options ^ in_options) & 2) { if (sl == 0 || sl == 3) return NWE_SIGNATURE_LEVEL_CONFLICT; if (sl == 1) { in_options |= NCP_SECURITY_LEVEL_SIGN_HEADERS; error = 1; } } if (error) { error = ncp_negotiate_size_and_options(conn, buffsize, in_options, &neg_buffsize, &options); if ((options ^ in_options) & 3) { return NWE_SIGNATURE_LEVEL_CONFLICT; } } } else { in_options &= ~NCP_SECURITY_LEVEL_SIGN_HEADERS; error = ncp_negotiate_buffersize(conn, NCP_DEFAULT_BUFSIZE, &neg_buffsize); } if (error) return error; if ((neg_buffsize < 512) || (neg_buffsize > NCP_MAX_BUFSIZE)) return EINVAL; conn->buffer_size = neg_buffsize; if (in_options & NCP_SECURITY_LEVEL_SIGN_HEADERS) conn->flags |= NCPFL_SIGNWANTED; if (conn->li.saddr.sa_family == AF_IPX) ncp_sock_checksum(conn, in_options & NCP_IPX_CHECKSUM); return 0; } void ncp_check_rq(struct ncp_conn *conn) { return; if (conn->flags & NCPFL_INTR) return; /* first, check for signals */ if (ncp_chkintr(conn, conn->td)) conn->flags |= NCPFL_INTR; return; } int ncp_get_bindery_object_id(struct ncp_conn *conn, u_int16_t object_type, char *object_name, struct ncp_bindery_object *target, struct thread *td, struct ucred *cred) { struct ncp_rq *rqp; int error; error = ncp_rq_alloc_subfn(23, 53, conn, conn->td, conn->ucred, &rqp); mb_put_uint16be(&rqp->rq, object_type); ncp_rq_pstring(rqp, object_name); rqp->nr_minrplen = 54; error = ncp_request(rqp); if (error) return error; md_get_uint32be(&rqp->rp, &target->object_id); md_get_uint16be(&rqp->rp, &target->object_type); md_get_mem(&rqp->rp, (caddr_t)target->object_name, 48, MB_MSYSTEM); ncp_rq_done(rqp); return 0; } /* * target is a 8-byte buffer */ int ncp_get_encryption_key(struct ncp_conn *conn, char *target) { struct ncp_rq *rqp; int error; error = ncp_rq_alloc_subfn(23, 23, conn, conn->td, conn->ucred, &rqp); if (error) return error; rqp->nr_minrplen = 8; error = ncp_request(rqp); if (error) return error; md_get_mem(&rqp->rp, target, 8, MB_MSYSTEM); ncp_rq_done(rqp); return error; } /* * Initialize packet signatures. They a slightly modified MD4. * The first 16 bytes of logindata are the shuffled password, * the last 8 bytes the encryption key as received from the server. */ static int ncp_sign_start(struct ncp_conn *conn, char *logindata) { char msg[64]; u_int32_t state[4]; memcpy(msg, logindata, 24); memcpy(msg + 24, "Authorized NetWare Client", 25); bzero(msg + 24 + 25, sizeof(msg) - 24 - 25); conn->sign_state[0] = 0x67452301; conn->sign_state[1] = 0xefcdab89; conn->sign_state[2] = 0x98badcfe; conn->sign_state[3] = 0x10325476; ncp_sign(conn->sign_state, msg, state); conn->sign_root[0] = state[0]; conn->sign_root[1] = state[1]; conn->flags |= NCPFL_SIGNACTIVE; return 0; } int ncp_login_encrypted(struct ncp_conn *conn, struct ncp_bindery_object *object, const u_char *key, const u_char *passwd, struct thread *td, struct ucred *cred) { struct ncp_rq *rqp; struct mbchain *mbp; u_int32_t tmpID = htonl(object->object_id); u_char buf[16 + 8]; u_char encrypted[8]; int error; nw_keyhash((u_char*)&tmpID, passwd, strlen(passwd), buf); nw_encrypt(key, buf, encrypted); error = ncp_rq_alloc_subfn(23, 24, conn, td, cred, &rqp); if (error) return error; mbp = &rqp->rq; mb_put_mem(mbp, encrypted, 8, MB_MSYSTEM); mb_put_uint16be(mbp, object->object_type); ncp_rq_pstring(rqp, object->object_name); error = ncp_request(rqp); if (!error) ncp_rq_done(rqp); if ((conn->flags & NCPFL_SIGNWANTED) && (error == 0 || error == NWE_PASSWORD_EXPIRED)) { bcopy(key, buf + 16, 8); error = ncp_sign_start(conn, buf); } return error; } int ncp_login_unencrypted(struct ncp_conn *conn, u_int16_t object_type, const char *object_name, const u_char *passwd, struct thread *td, struct ucred *cred) { struct ncp_rq *rqp; int error; error = ncp_rq_alloc_subfn(23, 20, conn, td, cred, &rqp); if (error) return error; mb_put_uint16be(&rqp->rq, object_type); ncp_rq_pstring(rqp, object_name); ncp_rq_pstring(rqp, passwd); error = ncp_request(rqp); if (!error) ncp_rq_done(rqp); return error; } int ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred) { struct ncp_rq *rqp; struct mbchain *mbp; u_int16_t retlen = 0 ; int error = 0, len = 0, tsiz, burstio; tsiz = uiop->uio_resid; #ifdef NCPBURST burstio = (ncp_burst_enabled && tsiz > conn->buffer_size); #else burstio = 0; #endif while (tsiz > 0) { if (!burstio) { len = min(4096 - (uiop->uio_offset % 4096), tsiz); len = min(len, conn->buffer_size); error = ncp_rq_alloc(72, conn, uiop->uio_td, cred, &rqp); if (error) break; mbp = &rqp->rq; mb_put_uint8(mbp, 0); mb_put_mem(mbp, (caddr_t)file, 6, MB_MSYSTEM); mb_put_uint32be(mbp, uiop->uio_offset); mb_put_uint16be(mbp, len); rqp->nr_minrplen = 2; error = ncp_request(rqp); if (error) break; md_get_uint16be(&rqp->rp, &retlen); if (uiop->uio_offset & 1) md_get_mem(&rqp->rp, NULL, 1, MB_MSYSTEM); error = md_get_uio(&rqp->rp, uiop, retlen); ncp_rq_done(rqp); } else { #ifdef NCPBURST error = ncp_burst_read(conn, file, tsiz, &len, &retlen, uiop, cred); #endif } if (error) break; tsiz -= retlen; if (retlen < len) break; } return (error); } int ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred) { struct ncp_rq *rqp; struct mbchain *mbp; int error = 0, len, tsiz, backup; if (uiop->uio_iovcnt != 1) { printf("%s: can't handle iovcnt>1 !!!\n", __func__); return EIO; } tsiz = uiop->uio_resid; while (tsiz > 0) { len = min(4096 - (uiop->uio_offset % 4096), tsiz); len = min(len, conn->buffer_size); if (len == 0) { printf("gotcha!\n"); } /* rq head */ error = ncp_rq_alloc(73, conn, uiop->uio_td, cred, &rqp); if (error) break; mbp = &rqp->rq; mb_put_uint8(mbp, 0); mb_put_mem(mbp, (caddr_t)file, 6, MB_MSYSTEM); mb_put_uint32be(mbp, uiop->uio_offset); mb_put_uint16be(mbp, len); error = mb_put_uio(mbp, uiop, len); if (error) { ncp_rq_done(rqp); break; } error = ncp_request(rqp); if (!error) ncp_rq_done(rqp); if (len == 0) break; if (error) { backup = len; uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base - backup; uiop->uio_iov->iov_len += backup; uiop->uio_offset -= backup; uiop->uio_resid += backup; break; } tsiz -= len; } if (error) uiop->uio_resid = tsiz; switch (error) { case NWE_INSUFFICIENT_SPACE: error = ENOSPC; break; } return (error); } diff --git a/sys/netsmb/smb_usr.c b/sys/netsmb/smb_usr.c index 9e42fd46fbe8..fd0a326e7f18 100644 --- a/sys/netsmb/smb_usr.c +++ b/sys/netsmb/smb_usr.c @@ -1,362 +1,361 @@ /* * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * 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)); #ifdef NETSMB_NO_ANON_USER if (dp->ioc_user[0] == 0) return EINVAL; #endif 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) + if (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; }