1139823Simp/*- 275374Sbp * Copyright (c) 2000-2001 Boris Popov 375374Sbp * All rights reserved. 475374Sbp * 575374Sbp * Redistribution and use in source and binary forms, with or without 675374Sbp * modification, are permitted provided that the following conditions 775374Sbp * are met: 875374Sbp * 1. Redistributions of source code must retain the above copyright 975374Sbp * notice, this list of conditions and the following disclaimer. 1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright 1175374Sbp * notice, this list of conditions and the following disclaimer in the 1275374Sbp * documentation and/or other materials provided with the distribution. 1375374Sbp * 1475374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1575374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1675374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1775374Sbp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1875374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1975374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2075374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2175374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2275374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2375374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2475374Sbp * SUCH DAMAGE. 2575374Sbp */ 26116189Sobrien 27116189Sobrien#include <sys/cdefs.h> 28116189Sobrien__FBSDID("$FreeBSD$"); 29116189Sobrien 3075374Sbp#include <sys/param.h> 3175374Sbp#include <sys/kernel.h> 32250236Sdavide#include <sys/capability.h> 33129880Sphk#include <sys/module.h> 3475374Sbp#include <sys/systm.h> 3576166Smarkm#include <sys/conf.h> 3676166Smarkm#include <sys/fcntl.h> 3775374Sbp#include <sys/ioccom.h> 3876166Smarkm#include <sys/lock.h> 3975374Sbp#include <sys/malloc.h> 4076166Smarkm#include <sys/file.h> /* Must come after sys/malloc.h */ 41108524Salfred#include <sys/filedesc.h> 4275374Sbp#include <sys/mbuf.h> 4376166Smarkm#include <sys/poll.h> 4475374Sbp#include <sys/proc.h> 4576166Smarkm#include <sys/select.h> 4675374Sbp#include <sys/socket.h> 4775374Sbp#include <sys/socketvar.h> 4875374Sbp#include <sys/sysctl.h> 4976166Smarkm#include <sys/uio.h> 5075374Sbp#include <sys/vnode.h> 5175374Sbp 5275374Sbp#include <net/if.h> 5375374Sbp 5475374Sbp#include <netsmb/smb.h> 5575374Sbp#include <netsmb/smb_conn.h> 5675374Sbp#include <netsmb/smb_subr.h> 5775374Sbp#include <netsmb/smb_dev.h> 5875374Sbp 59250236Sdavidestatic struct cdev *nsmb_dev; 6075374Sbp 6175374Sbpstatic d_open_t nsmb_dev_open; 6275374Sbpstatic d_ioctl_t nsmb_dev_ioctl; 6375374Sbp 64120492SfjoeMODULE_DEPEND(netsmb, libiconv, 1, 1, 2); 6575374SbpMODULE_VERSION(netsmb, NSMB_VERSION); 6675374Sbp 6775374Sbpstatic int smb_version = NSMB_VERSION; 68250236Sdavidestruct sx smb_lock; 6975374Sbp 7075374Sbp 7175374SbpSYSCTL_DECL(_net_smb); 7275374SbpSYSCTL_INT(_net_smb, OID_AUTO, version, CTLFLAG_RD, &smb_version, 0, ""); 7375374Sbp 7475374Sbpstatic MALLOC_DEFINE(M_NSMBDEV, "NETSMBDEV", "NET/SMB device"); 7575374Sbp 7675374Sbpstatic struct cdevsw nsmb_cdevsw = { 77126080Sphk .d_version = D_VERSION, 78111815Sphk .d_open = nsmb_dev_open, 79111815Sphk .d_ioctl = nsmb_dev_ioctl, 80125706Stjr .d_name = NSMB_NAME 8175374Sbp}; 8275374Sbp 83250236Sdavidestatic int 84250236Sdavidensmb_dev_init(void) 85250236Sdavide{ 8675374Sbp 87250236Sdavide nsmb_dev = make_dev(&nsmb_cdevsw, 0, UID_ROOT, GID_OPERATOR, 88250236Sdavide 0600, "nsmb"); 89250236Sdavide if (nsmb_dev == NULL) 90250236Sdavide return (ENOMEM); 91250236Sdavide return (0); 92250236Sdavide} 93250236Sdavide 94250236Sdavidestatic void 95250236Sdavidensmb_dev_destroy(void) 9675374Sbp{ 9775374Sbp 98250236Sdavide MPASS(nsmb_dev != NULL); 99250236Sdavide destroy_dev(nsmb_dev); 100250236Sdavide nsmb_dev = NULL; 101250236Sdavide} 102184592Srwatson 103250236Sdavidestatic struct smb_dev * 104250236Sdavidesmbdev_alloc(struct cdev *dev) 105250236Sdavide{ 106250236Sdavide struct smb_dev *sdp; 107250236Sdavide 108250236Sdavide sdp = malloc(sizeof(struct smb_dev), M_NSMBDEV, M_WAITOK | M_ZERO); 109250236Sdavide sdp->dev = dev; 110250236Sdavide sdp->sd_level = -1; 111250236Sdavide sdp->sd_flags |= NSMBFL_OPEN; 112250236Sdavide sdp->refcount = 1; 113250236Sdavide return (sdp); 114250236Sdavide} 115250236Sdavide 116250236Sdavidevoid 117250236Sdavidesdp_dtor(void *arg) 118250236Sdavide{ 119250236Sdavide struct smb_dev *dev; 120250236Sdavide 121250236Sdavide dev = (struct smb_dev *)arg; 122250236Sdavide SMB_LOCK(); 123250236Sdavide sdp_trydestroy(dev); 124250236Sdavide SMB_UNLOCK(); 12575374Sbp} 12675374Sbp 12775374Sbpstatic int 128130585Sphknsmb_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 12975374Sbp{ 13075374Sbp struct smb_dev *sdp; 131250236Sdavide int error; 13275374Sbp 133250236Sdavide sdp = smbdev_alloc(dev); 134250236Sdavide error = devfs_set_cdevpriv(sdp, sdp_dtor); 135250236Sdavide if (error) { 136250236Sdavide free(sdp, M_NSMBDEV); 137250236Sdavide return (error); 13875374Sbp } 139250236Sdavide return (0); 14075374Sbp} 14175374Sbp 142250236Sdavidevoid 143250236Sdavidesdp_trydestroy(struct smb_dev *sdp) 14475374Sbp{ 14575374Sbp struct smb_vc *vcp; 14675374Sbp struct smb_share *ssp; 147242386Sdavide struct smb_cred *scred; 14875374Sbp 149250236Sdavide SMB_LOCKASSERT(); 150250236Sdavide if (!sdp) 151250236Sdavide panic("No smb_dev upon device close"); 152250236Sdavide MPASS(sdp->refcount > 0); 153250236Sdavide sdp->refcount--; 154250236Sdavide if (sdp->refcount) 155250236Sdavide return; 156242386Sdavide scred = malloc(sizeof(struct smb_cred), M_NSMBDEV, M_WAITOK); 157250236Sdavide smb_makescred(scred, curthread, NULL); 15875374Sbp ssp = sdp->sd_share; 159250237Sdavide if (ssp != NULL) { 160250237Sdavide smb_share_lock(ssp); 161242386Sdavide smb_share_rele(ssp, scred); 162250237Sdavide } 16375374Sbp vcp = sdp->sd_vc; 164250237Sdavide if (vcp != NULL) { 165250237Sdavide smb_vc_lock(vcp); 166242386Sdavide smb_vc_rele(vcp, scred); 167250237Sdavide } 168250236Sdavide free(scred, M_NSMBDEV); 16975374Sbp free(sdp, M_NSMBDEV); 170250236Sdavide return; 17175374Sbp} 17275374Sbp 17375374Sbp 17475374Sbpstatic int 175130585Sphknsmb_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 17675374Sbp{ 17775374Sbp struct smb_dev *sdp; 17875374Sbp struct smb_vc *vcp; 17975374Sbp struct smb_share *ssp; 180242386Sdavide struct smb_cred *scred; 18175374Sbp int error = 0; 18275374Sbp 183250236Sdavide error = devfs_get_cdevpriv((void **)&sdp); 184250236Sdavide if (error) 185250236Sdavide return (error); 186242386Sdavide scred = malloc(sizeof(struct smb_cred), M_NSMBDEV, M_WAITOK); 187250236Sdavide SMB_LOCK(); 188242386Sdavide smb_makescred(scred, td, NULL); 18975374Sbp switch (cmd) { 19075374Sbp case SMBIOC_OPENSESSION: 191242386Sdavide if (sdp->sd_vc) { 192242386Sdavide error = EISCONN; 193242386Sdavide goto out; 194242386Sdavide } 19575374Sbp error = smb_usr_opensession((struct smbioc_ossn*)data, 196242386Sdavide scred, &vcp); 19775374Sbp if (error) 19875374Sbp break; 19975374Sbp sdp->sd_vc = vcp; 200250237Sdavide smb_vc_unlock(vcp); 20175374Sbp sdp->sd_level = SMBL_VC; 20275374Sbp break; 20375374Sbp case SMBIOC_OPENSHARE: 204242386Sdavide if (sdp->sd_share) { 205242386Sdavide error = EISCONN; 206242386Sdavide goto out; 207242386Sdavide } 208242386Sdavide if (sdp->sd_vc == NULL) { 209242386Sdavide error = ENOTCONN; 210242386Sdavide goto out; 211242386Sdavide } 21275374Sbp error = smb_usr_openshare(sdp->sd_vc, 213242386Sdavide (struct smbioc_oshare*)data, scred, &ssp); 21475374Sbp if (error) 21575374Sbp break; 21675374Sbp sdp->sd_share = ssp; 217250237Sdavide smb_share_unlock(ssp); 21875374Sbp sdp->sd_level = SMBL_SHARE; 21975374Sbp break; 22075374Sbp case SMBIOC_REQUEST: 221242386Sdavide if (sdp->sd_share == NULL) { 222242386Sdavide error = ENOTCONN; 223242386Sdavide goto out; 224242386Sdavide } 22575374Sbp error = smb_usr_simplerequest(sdp->sd_share, 226242386Sdavide (struct smbioc_rq*)data, scred); 22775374Sbp break; 22875374Sbp case SMBIOC_T2RQ: 229242386Sdavide if (sdp->sd_share == NULL) { 230242386Sdavide error = ENOTCONN; 231242386Sdavide goto out; 232242386Sdavide } 23375374Sbp error = smb_usr_t2request(sdp->sd_share, 234242386Sdavide (struct smbioc_t2rq*)data, scred); 23575374Sbp break; 23675374Sbp case SMBIOC_SETFLAGS: { 23775374Sbp struct smbioc_flags *fl = (struct smbioc_flags*)data; 23875374Sbp int on; 23975374Sbp 24075374Sbp if (fl->ioc_level == SMBL_VC) { 24175374Sbp if (fl->ioc_mask & SMBV_PERMANENT) { 24275374Sbp on = fl->ioc_flags & SMBV_PERMANENT; 243242386Sdavide if ((vcp = sdp->sd_vc) == NULL) { 244242386Sdavide error = ENOTCONN; 245242386Sdavide goto out; 246242386Sdavide } 247250237Sdavide error = smb_vc_get(vcp, scred); 24875374Sbp if (error) 24975374Sbp break; 25075374Sbp if (on && (vcp->obj.co_flags & SMBV_PERMANENT) == 0) { 25175374Sbp vcp->obj.co_flags |= SMBV_PERMANENT; 25287192Sbp smb_vc_ref(vcp); 25375374Sbp } else if (!on && (vcp->obj.co_flags & SMBV_PERMANENT)) { 25475374Sbp vcp->obj.co_flags &= ~SMBV_PERMANENT; 255242386Sdavide smb_vc_rele(vcp, scred); 25675374Sbp } 257242386Sdavide smb_vc_put(vcp, scred); 25875374Sbp } else 25975374Sbp error = EINVAL; 26075374Sbp } else if (fl->ioc_level == SMBL_SHARE) { 26175374Sbp if (fl->ioc_mask & SMBS_PERMANENT) { 26275374Sbp on = fl->ioc_flags & SMBS_PERMANENT; 263242386Sdavide if ((ssp = sdp->sd_share) == NULL) { 264242386Sdavide error = ENOTCONN; 265242386Sdavide goto out; 266242386Sdavide } 267250237Sdavide error = smb_share_get(ssp, scred); 26875374Sbp if (error) 26975374Sbp break; 27075374Sbp if (on && (ssp->obj.co_flags & SMBS_PERMANENT) == 0) { 27175374Sbp ssp->obj.co_flags |= SMBS_PERMANENT; 27287192Sbp smb_share_ref(ssp); 27375374Sbp } else if (!on && (ssp->obj.co_flags & SMBS_PERMANENT)) { 27475374Sbp ssp->obj.co_flags &= ~SMBS_PERMANENT; 275242386Sdavide smb_share_rele(ssp, scred); 27675374Sbp } 277242386Sdavide smb_share_put(ssp, scred); 27875374Sbp } else 27975374Sbp error = EINVAL; 28075374Sbp break; 28175374Sbp } else 28275374Sbp error = EINVAL; 28375374Sbp break; 28475374Sbp } 28575374Sbp case SMBIOC_LOOKUP: 286242386Sdavide if (sdp->sd_vc || sdp->sd_share) { 287242386Sdavide error = EISCONN; 288242386Sdavide goto out; 289242386Sdavide } 29075374Sbp vcp = NULL; 29175374Sbp ssp = NULL; 292242386Sdavide error = smb_usr_lookup((struct smbioc_lookup*)data, scred, &vcp, &ssp); 29375374Sbp if (error) 29475374Sbp break; 29575374Sbp if (vcp) { 29675374Sbp sdp->sd_vc = vcp; 297250237Sdavide smb_vc_unlock(vcp); 29875374Sbp sdp->sd_level = SMBL_VC; 29975374Sbp } 30075374Sbp if (ssp) { 30175374Sbp sdp->sd_share = ssp; 302250237Sdavide smb_share_unlock(ssp); 30375374Sbp sdp->sd_level = SMBL_SHARE; 30475374Sbp } 30575374Sbp break; 30675374Sbp case SMBIOC_READ: case SMBIOC_WRITE: { 30775374Sbp struct smbioc_rw *rwrq = (struct smbioc_rw*)data; 30875374Sbp struct uio auio; 30975374Sbp struct iovec iov; 31075374Sbp 311242386Sdavide if ((ssp = sdp->sd_share) == NULL) { 312242386Sdavide error = ENOTCONN; 313242386Sdavide goto out; 314242386Sdavide } 31575374Sbp iov.iov_base = rwrq->ioc_base; 31675374Sbp iov.iov_len = rwrq->ioc_cnt; 31775374Sbp auio.uio_iov = &iov; 31875374Sbp auio.uio_iovcnt = 1; 31975374Sbp auio.uio_offset = rwrq->ioc_offset; 32075374Sbp auio.uio_resid = rwrq->ioc_cnt; 32175374Sbp auio.uio_segflg = UIO_USERSPACE; 32275374Sbp auio.uio_rw = (cmd == SMBIOC_READ) ? UIO_READ : UIO_WRITE; 32387192Sbp auio.uio_td = td; 32475374Sbp if (cmd == SMBIOC_READ) 325242386Sdavide error = smb_read(ssp, rwrq->ioc_fh, &auio, scred); 32675374Sbp else 327242386Sdavide error = smb_write(ssp, rwrq->ioc_fh, &auio, scred); 32875374Sbp rwrq->ioc_cnt -= auio.uio_resid; 32975374Sbp break; 33075374Sbp } 33175374Sbp default: 33275374Sbp error = ENODEV; 33375374Sbp } 334242386Sdavideout: 335242386Sdavide free(scred, M_NSMBDEV); 336250236Sdavide SMB_UNLOCK(); 33775374Sbp return error; 33875374Sbp} 33975374Sbp 34075374Sbpstatic int 34175374Sbpnsmb_dev_load(module_t mod, int cmd, void *arg) 34275374Sbp{ 34375374Sbp int error = 0; 34475374Sbp 34575374Sbp switch (cmd) { 34675374Sbp case MOD_LOAD: 34775374Sbp error = smb_sm_init(); 34875374Sbp if (error) 34975374Sbp break; 35075374Sbp error = smb_iod_init(); 35175374Sbp if (error) { 35275374Sbp smb_sm_done(); 35375374Sbp break; 35475374Sbp } 355250236Sdavide error = nsmb_dev_init(); 356250236Sdavide if (error) 357250236Sdavide break; 358250236Sdavide sx_init(&smb_lock, "samba device lock"); 35975374Sbp break; 36075374Sbp case MOD_UNLOAD: 36175374Sbp smb_iod_done(); 36275374Sbp error = smb_sm_done(); 363152676Sbp if (error) 364152676Sbp break; 365250236Sdavide nsmb_dev_destroy(); 366250236Sdavide sx_destroy(&smb_lock); 36775374Sbp break; 36875374Sbp default: 36975374Sbp error = EINVAL; 37075374Sbp break; 37175374Sbp } 37275374Sbp return error; 37375374Sbp} 37475374Sbp 37575374SbpDEV_MODULE (dev_netsmb, nsmb_dev_load, 0); 37675374Sbp 37775374Sbpint 37875374Sbpsmb_dev2share(int fd, int mode, struct smb_cred *scred, 379250236Sdavide struct smb_share **sspp, struct smb_dev **ssdp) 38075374Sbp{ 381255219Spjd cap_rights_t rights; 382250236Sdavide struct file *fp, *fptmp; 38375374Sbp struct smb_dev *sdp; 38475374Sbp struct smb_share *ssp; 385250236Sdavide struct thread *td; 38675374Sbp int error; 38775374Sbp 388250236Sdavide td = curthread; 389255219Spjd error = fget(td, fd, cap_rights_init(&rights, CAP_READ), &fp); 390250236Sdavide if (error) 391250236Sdavide return (error); 392250236Sdavide fptmp = td->td_fpop; 393250236Sdavide td->td_fpop = fp; 394250236Sdavide error = devfs_get_cdevpriv((void **)&sdp); 395250236Sdavide td->td_fpop = fptmp; 396250236Sdavide fdrop(fp, td); 397250236Sdavide if (error || sdp == NULL) 398250236Sdavide return (error); 399250236Sdavide SMB_LOCK(); 400250236Sdavide *ssdp = sdp; 40175374Sbp ssp = sdp->sd_share; 40289306Salfred if (ssp == NULL) { 403250236Sdavide SMB_UNLOCK(); 404250236Sdavide return (ENOTCONN); 40589306Salfred } 406250237Sdavide error = smb_share_get(ssp, scred); 407250236Sdavide if (error == 0) { 408250236Sdavide sdp->refcount++; 40989306Salfred *sspp = ssp; 410250236Sdavide } 411250236Sdavide SMB_UNLOCK(); 41289306Salfred return error; 41375374Sbp} 41475374Sbp 415