14bff34e3Sthurlow /* 24bff34e3Sthurlow * Copyright (c) 2000-2001 Boris Popov 34bff34e3Sthurlow * All rights reserved. 44bff34e3Sthurlow * 54bff34e3Sthurlow * Redistribution and use in source and binary forms, with or without 64bff34e3Sthurlow * modification, are permitted provided that the following conditions 74bff34e3Sthurlow * are met: 84bff34e3Sthurlow * 1. Redistributions of source code must retain the above copyright 94bff34e3Sthurlow * notice, this list of conditions and the following disclaimer. 104bff34e3Sthurlow * 2. Redistributions in binary form must reproduce the above copyright 114bff34e3Sthurlow * notice, this list of conditions and the following disclaimer in the 124bff34e3Sthurlow * documentation and/or other materials provided with the distribution. 134bff34e3Sthurlow * 3. All advertising materials mentioning features or use of this software 144bff34e3Sthurlow * must display the following acknowledgement: 154bff34e3Sthurlow * This product includes software developed by Boris Popov. 164bff34e3Sthurlow * 4. Neither the name of the author nor the names of any co-contributors 174bff34e3Sthurlow * may be used to endorse or promote products derived from this software 184bff34e3Sthurlow * without specific prior written permission. 194bff34e3Sthurlow * 204bff34e3Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 214bff34e3Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224bff34e3Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234bff34e3Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 244bff34e3Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254bff34e3Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264bff34e3Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274bff34e3Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284bff34e3Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294bff34e3Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304bff34e3Sthurlow * SUCH DAMAGE. 314bff34e3Sthurlow * 324bff34e3Sthurlow * $Id: smb_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $ 334bff34e3Sthurlow */ 344bff34e3Sthurlow 359c9af259SGordon Ross /* 36*430b4c46SGordon Ross * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 37613a2f6bSGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 389c9af259SGordon Ross * Use is subject to license terms. 399c9af259SGordon Ross */ 404bff34e3Sthurlow 414bff34e3Sthurlow #include <sys/param.h> 424bff34e3Sthurlow #include <sys/kmem.h> 434bff34e3Sthurlow #include <sys/systm.h> 444bff34e3Sthurlow #include <sys/policy.h> 454bff34e3Sthurlow #include <sys/conf.h> 464bff34e3Sthurlow #include <sys/proc.h> 474bff34e3Sthurlow #include <sys/fcntl.h> 48613a2f6bSGordon Ross #include <sys/file.h> 494bff34e3Sthurlow #include <sys/socket.h> 50613a2f6bSGordon Ross #include <sys/sunddi.h> 514bff34e3Sthurlow #include <sys/cmn_err.h> 524bff34e3Sthurlow 534bff34e3Sthurlow #include <netsmb/smb_osdep.h> 544bff34e3Sthurlow 554bff34e3Sthurlow #include <netsmb/smb.h> 564bff34e3Sthurlow #include <netsmb/smb_conn.h> 574bff34e3Sthurlow #include <netsmb/smb_rq.h> 584bff34e3Sthurlow #include <netsmb/smb_subr.h> 594bff34e3Sthurlow #include <netsmb/smb_dev.h> 604bff34e3Sthurlow 61613a2f6bSGordon Ross static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg); 62613a2f6bSGordon Ross 634bff34e3Sthurlow /* 64613a2f6bSGordon Ross * Ioctl function for SMBIOC_FLAGS2 654bff34e3Sthurlow */ 66613a2f6bSGordon Ross int 67613a2f6bSGordon Ross smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags) 68613a2f6bSGordon Ross { 69613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 70613a2f6bSGordon Ross 71613a2f6bSGordon Ross /* This ioctl requires a session. */ 72613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 73613a2f6bSGordon Ross return (ENOTCONN); 74613a2f6bSGordon Ross 75613a2f6bSGordon Ross /* 76613a2f6bSGordon Ross * Return the flags2 value. 77613a2f6bSGordon Ross */ 78613a2f6bSGordon Ross if (ddi_copyout(&vcp->vc_hflags2, (void *)arg, 79613a2f6bSGordon Ross sizeof (u_int16_t), flags)) 80613a2f6bSGordon Ross return (EFAULT); 81613a2f6bSGordon Ross 82613a2f6bSGordon Ross return (0); 83613a2f6bSGordon Ross } 844bff34e3Sthurlow 854bff34e3Sthurlow /* 86613a2f6bSGordon Ross * Ioctl function for SMBIOC_GETSSNKEY 87613a2f6bSGordon Ross * Size copied out is SMBIOC_HASH_SZ. 88613a2f6bSGordon Ross * 89613a2f6bSGordon Ross * The RPC library needs this for encrypting things 90613a2f6bSGordon Ross * like "set password" requests. This is called 91613a2f6bSGordon Ross * with an active RPC binding, so the connection 92613a2f6bSGordon Ross * will already be active (but this checks). 934bff34e3Sthurlow */ 94613a2f6bSGordon Ross int 95613a2f6bSGordon Ross smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags) 964bff34e3Sthurlow { 97613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 98613a2f6bSGordon Ross 99613a2f6bSGordon Ross /* This ioctl requires an active session. */ 100613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 101613a2f6bSGordon Ross return (ENOTCONN); 102613a2f6bSGordon Ross if (vcp->vc_state != SMBIOD_ST_VCACTIVE) 103613a2f6bSGordon Ross return (ENOTCONN); 1044bff34e3Sthurlow 1054bff34e3Sthurlow /* 106613a2f6bSGordon Ross * Return the session key. 1074bff34e3Sthurlow */ 108613a2f6bSGordon Ross if (ddi_copyout(vcp->vc_ssn_key, (void *)arg, 109613a2f6bSGordon Ross SMBIOC_HASH_SZ, flags)) 110613a2f6bSGordon Ross return (EFAULT); 111613a2f6bSGordon Ross 112613a2f6bSGordon Ross return (0); 113613a2f6bSGordon Ross } 114613a2f6bSGordon Ross 115613a2f6bSGordon Ross /* 116613a2f6bSGordon Ross * Ioctl function for SMBIOC_REQUEST 117613a2f6bSGordon Ross */ 118613a2f6bSGordon Ross int 119613a2f6bSGordon Ross smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 120613a2f6bSGordon Ross { 121613a2f6bSGordon Ross struct smb_cred scred; 122613a2f6bSGordon Ross struct smb_share *ssp; 123613a2f6bSGordon Ross smbioc_rq_t *ioc = NULL; 124613a2f6bSGordon Ross struct smb_rq *rqp = NULL; 125613a2f6bSGordon Ross struct mbchain *mbp; 126613a2f6bSGordon Ross struct mdchain *mdp; 127613a2f6bSGordon Ross uint32_t rsz; 128613a2f6bSGordon Ross int err, mbseg; 129613a2f6bSGordon Ross 130613a2f6bSGordon Ross /* This ioctl requires a share. */ 131613a2f6bSGordon Ross if ((ssp = sdp->sd_share) == NULL) 132613a2f6bSGordon Ross return (ENOTCONN); 133613a2f6bSGordon Ross 134613a2f6bSGordon Ross smb_credinit(&scred, cr); 135613a2f6bSGordon Ross ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 136613a2f6bSGordon Ross if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 137613a2f6bSGordon Ross err = EFAULT; 138613a2f6bSGordon Ross goto out; 1394bff34e3Sthurlow } 1404bff34e3Sthurlow 141613a2f6bSGordon Ross /* See ddi_copyin, ddi_copyout */ 142613a2f6bSGordon Ross mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; 1434bff34e3Sthurlow 1444bff34e3Sthurlow /* 145613a2f6bSGordon Ross * Lots of SMB commands could be safe, but 146613a2f6bSGordon Ross * these are the only ones used by libsmbfs. 1474bff34e3Sthurlow */ 148613a2f6bSGordon Ross switch (ioc->ioc_cmd) { 149613a2f6bSGordon Ross /* These are OK */ 150613a2f6bSGordon Ross case SMB_COM_CLOSE: 151613a2f6bSGordon Ross case SMB_COM_FLUSH: 152613a2f6bSGordon Ross case SMB_COM_NT_CREATE_ANDX: 153613a2f6bSGordon Ross case SMB_COM_OPEN_PRINT_FILE: 154613a2f6bSGordon Ross case SMB_COM_CLOSE_PRINT_FILE: 155613a2f6bSGordon Ross break; 156613a2f6bSGordon Ross 157613a2f6bSGordon Ross default: 158613a2f6bSGordon Ross err = EPERM; 159613a2f6bSGordon Ross goto out; 1604bff34e3Sthurlow } 1614bff34e3Sthurlow 162613a2f6bSGordon Ross err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp); 163613a2f6bSGordon Ross if (err) 164613a2f6bSGordon Ross goto out; 165613a2f6bSGordon Ross 166613a2f6bSGordon Ross mbp = &rqp->sr_rq; 167613a2f6bSGordon Ross err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg); 168613a2f6bSGordon Ross 169613a2f6bSGordon Ross err = smb_rq_simple(rqp); 170613a2f6bSGordon Ross if (err == 0) { 171613a2f6bSGordon Ross /* 172613a2f6bSGordon Ross * This may have been an open, so save the 173613a2f6bSGordon Ross * generation ID of the share, which we 174613a2f6bSGordon Ross * check before trying read or write. 175613a2f6bSGordon Ross */ 176613a2f6bSGordon Ross sdp->sd_vcgenid = ssp->ss_vcgenid; 177613a2f6bSGordon Ross 178613a2f6bSGordon Ross /* 179613a2f6bSGordon Ross * Have reply data. to copyout. 180613a2f6bSGordon Ross * SMB header already parsed. 181613a2f6bSGordon Ross */ 182613a2f6bSGordon Ross mdp = &rqp->sr_rp; 183613a2f6bSGordon Ross rsz = msgdsize(mdp->md_top) - SMB_HDRLEN; 184613a2f6bSGordon Ross if (ioc->ioc_rbufsz < rsz) { 185613a2f6bSGordon Ross err = EOVERFLOW; 186613a2f6bSGordon Ross goto out; 187613a2f6bSGordon Ross } 188613a2f6bSGordon Ross ioc->ioc_rbufsz = rsz; 189613a2f6bSGordon Ross err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg); 190613a2f6bSGordon Ross if (err) 191613a2f6bSGordon Ross goto out; 192613a2f6bSGordon Ross 1934bff34e3Sthurlow } 1944bff34e3Sthurlow 195613a2f6bSGordon Ross ioc->ioc_errclass = rqp->sr_errclass; 196613a2f6bSGordon Ross ioc->ioc_serror = rqp->sr_serror; 197613a2f6bSGordon Ross ioc->ioc_error = rqp->sr_error; 19802d09e03SGordon Ross (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); 1994bff34e3Sthurlow 200613a2f6bSGordon Ross out: 201613a2f6bSGordon Ross if (rqp != NULL) 202613a2f6bSGordon Ross smb_rq_done(rqp); /* free rqp */ 203*430b4c46SGordon Ross kmem_free(ioc, sizeof (*ioc)); 204613a2f6bSGordon Ross smb_credrele(&scred); 205613a2f6bSGordon Ross 206613a2f6bSGordon Ross return (err); 2074bff34e3Sthurlow 2084bff34e3Sthurlow } 2094bff34e3Sthurlow 210613a2f6bSGordon Ross /* 211613a2f6bSGordon Ross * Ioctl function for SMBIOC_T2RQ 212613a2f6bSGordon Ross */ 213613a2f6bSGordon Ross int 214613a2f6bSGordon Ross smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 2154bff34e3Sthurlow { 216613a2f6bSGordon Ross struct smb_cred scred; 217613a2f6bSGordon Ross struct smb_share *ssp; 218613a2f6bSGordon Ross smbioc_t2rq_t *ioc = NULL; 219613a2f6bSGordon Ross struct smb_t2rq *t2p = NULL; 220613a2f6bSGordon Ross struct mdchain *mdp; 221613a2f6bSGordon Ross int err, len, mbseg; 222613a2f6bSGordon Ross 223613a2f6bSGordon Ross /* This ioctl requires a share. */ 224613a2f6bSGordon Ross if ((ssp = sdp->sd_share) == NULL) 225613a2f6bSGordon Ross return (ENOTCONN); 2264bff34e3Sthurlow 227613a2f6bSGordon Ross smb_credinit(&scred, cr); 228613a2f6bSGordon Ross ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 229613a2f6bSGordon Ross if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 230613a2f6bSGordon Ross err = EFAULT; 231613a2f6bSGordon Ross goto out; 2324bff34e3Sthurlow } 233613a2f6bSGordon Ross 234613a2f6bSGordon Ross /* See ddi_copyin, ddi_copyout */ 235613a2f6bSGordon Ross mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; 236613a2f6bSGordon Ross 237613a2f6bSGordon Ross if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) { 238613a2f6bSGordon Ross err = EINVAL; 239613a2f6bSGordon Ross goto out; 240613a2f6bSGordon Ross } 241613a2f6bSGordon Ross 242*430b4c46SGordon Ross /* 243*430b4c46SGordon Ross * Fill in the FID for libsmbfs transact named pipe. 244*430b4c46SGordon Ross */ 245*430b4c46SGordon Ross if (ioc->ioc_setupcnt > 1 && ioc->ioc_setup[1] == 0xFFFF) { 246*430b4c46SGordon Ross if (sdp->sd_vcgenid != ssp->ss_vcgenid) { 247*430b4c46SGordon Ross err = ESTALE; 248*430b4c46SGordon Ross goto out; 249*430b4c46SGordon Ross } 250*430b4c46SGordon Ross ioc->ioc_setup[1] = (uint16_t)sdp->sd_smbfid; 251*430b4c46SGordon Ross } 252*430b4c46SGordon Ross 253613a2f6bSGordon Ross t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP); 254613a2f6bSGordon Ross err = smb_t2_init(t2p, SSTOCP(ssp), 255613a2f6bSGordon Ross ioc->ioc_setup, ioc->ioc_setupcnt, &scred); 256613a2f6bSGordon Ross if (err) 257613a2f6bSGordon Ross goto out; 258*430b4c46SGordon Ross t2p->t2_setupcount = ioc->ioc_setupcnt; 259*430b4c46SGordon Ross t2p->t2_setupdata = ioc->ioc_setup; 260613a2f6bSGordon Ross 261613a2f6bSGordon Ross /* This ioc member is a fixed-size array. */ 262613a2f6bSGordon Ross if (ioc->ioc_name[0]) { 263613a2f6bSGordon Ross /* Get the name length - carefully! */ 264613a2f6bSGordon Ross ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0'; 265613a2f6bSGordon Ross t2p->t_name_len = strlen(ioc->ioc_name); 266613a2f6bSGordon Ross t2p->t_name = ioc->ioc_name; 267613a2f6bSGordon Ross } 268613a2f6bSGordon Ross t2p->t2_maxscount = 0; 269613a2f6bSGordon Ross t2p->t2_maxpcount = ioc->ioc_rparamcnt; 270613a2f6bSGordon Ross t2p->t2_maxdcount = ioc->ioc_rdatacnt; 271613a2f6bSGordon Ross 272613a2f6bSGordon Ross /* Transmit parameters */ 273613a2f6bSGordon Ross err = smb_cpdatain(&t2p->t2_tparam, 274613a2f6bSGordon Ross ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg); 275613a2f6bSGordon Ross if (err) 276613a2f6bSGordon Ross goto out; 277613a2f6bSGordon Ross 278613a2f6bSGordon Ross /* Transmit data */ 279613a2f6bSGordon Ross err = smb_cpdatain(&t2p->t2_tdata, 280613a2f6bSGordon Ross ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg); 281613a2f6bSGordon Ross if (err) 282613a2f6bSGordon Ross goto out; 283613a2f6bSGordon Ross 284613a2f6bSGordon Ross err = smb_t2_request(t2p); 285613a2f6bSGordon Ross 286613a2f6bSGordon Ross /* Copyout returned parameters. */ 287613a2f6bSGordon Ross mdp = &t2p->t2_rparam; 288613a2f6bSGordon Ross if (err == 0 && mdp->md_top != NULL) { 289613a2f6bSGordon Ross /* User's buffer large enough? */ 290613a2f6bSGordon Ross len = m_fixhdr(mdp->md_top); 291613a2f6bSGordon Ross if (len > ioc->ioc_rparamcnt) { 292613a2f6bSGordon Ross err = EMSGSIZE; 293613a2f6bSGordon Ross goto out; 294613a2f6bSGordon Ross } 295613a2f6bSGordon Ross ioc->ioc_rparamcnt = (ushort_t)len; 296613a2f6bSGordon Ross err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg); 297613a2f6bSGordon Ross if (err) 298613a2f6bSGordon Ross goto out; 299613a2f6bSGordon Ross } else 300613a2f6bSGordon Ross ioc->ioc_rparamcnt = 0; 301613a2f6bSGordon Ross 302613a2f6bSGordon Ross /* Copyout returned data. */ 303613a2f6bSGordon Ross mdp = &t2p->t2_rdata; 304613a2f6bSGordon Ross if (err == 0 && mdp->md_top != NULL) { 305613a2f6bSGordon Ross /* User's buffer large enough? */ 306613a2f6bSGordon Ross len = m_fixhdr(mdp->md_top); 307613a2f6bSGordon Ross if (len > ioc->ioc_rdatacnt) { 308613a2f6bSGordon Ross err = EMSGSIZE; 309613a2f6bSGordon Ross goto out; 310613a2f6bSGordon Ross } 311613a2f6bSGordon Ross ioc->ioc_rdatacnt = (ushort_t)len; 312613a2f6bSGordon Ross err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg); 313613a2f6bSGordon Ross if (err) 314613a2f6bSGordon Ross goto out; 315613a2f6bSGordon Ross } else 316613a2f6bSGordon Ross ioc->ioc_rdatacnt = 0; 317613a2f6bSGordon Ross 318613a2f6bSGordon Ross ioc->ioc_errclass = t2p->t2_sr_errclass; 319613a2f6bSGordon Ross ioc->ioc_serror = t2p->t2_sr_serror; 320613a2f6bSGordon Ross ioc->ioc_error = t2p->t2_sr_error; 321613a2f6bSGordon Ross ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2; 322613a2f6bSGordon Ross 32302d09e03SGordon Ross (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); 324613a2f6bSGordon Ross 325613a2f6bSGordon Ross 326613a2f6bSGordon Ross out: 327613a2f6bSGordon Ross if (t2p != NULL) { 328613a2f6bSGordon Ross /* Note: t2p->t_name no longer allocated */ 329613a2f6bSGordon Ross smb_t2_done(t2p); 330613a2f6bSGordon Ross kmem_free(t2p, sizeof (*t2p)); 331613a2f6bSGordon Ross } 332*430b4c46SGordon Ross kmem_free(ioc, sizeof (*ioc)); 333613a2f6bSGordon Ross smb_credrele(&scred); 334613a2f6bSGordon Ross 335613a2f6bSGordon Ross return (err); 3364bff34e3Sthurlow } 3374bff34e3Sthurlow 338613a2f6bSGordon Ross /* helper for _t2request */ 3394bff34e3Sthurlow static int 340613a2f6bSGordon Ross smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg) 3414bff34e3Sthurlow { 342613a2f6bSGordon Ross int error; 343613a2f6bSGordon Ross 344613a2f6bSGordon Ross if (len == 0) 345613a2f6bSGordon Ross return (0); 346613a2f6bSGordon Ross error = mb_init(mbp); 347613a2f6bSGordon Ross if (error) 348613a2f6bSGordon Ross return (error); 349613a2f6bSGordon Ross return (mb_put_mem(mbp, data, len, mbseg)); 3504bff34e3Sthurlow } 3514bff34e3Sthurlow 352613a2f6bSGordon Ross /* 353613a2f6bSGordon Ross * Helper for nsmb_ioctl cases 354613a2f6bSGordon Ross * SMBIOC_READ, SMBIOC_WRITE 355613a2f6bSGordon Ross */ 3561b34bc4aSbs int 357613a2f6bSGordon Ross smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 3581b34bc4aSbs { 359613a2f6bSGordon Ross struct smb_cred scred; 360613a2f6bSGordon Ross struct smb_share *ssp; 361613a2f6bSGordon Ross smbioc_rw_t *ioc = NULL; 362613a2f6bSGordon Ross struct iovec aiov[1]; 363613a2f6bSGordon Ross struct uio auio; 364*430b4c46SGordon Ross uint16_t fh; 365613a2f6bSGordon Ross int err; 366613a2f6bSGordon Ross uio_rw_t rw; 3671b34bc4aSbs 368613a2f6bSGordon Ross /* This ioctl requires a share. */ 369613a2f6bSGordon Ross if ((ssp = sdp->sd_share) == NULL) 370613a2f6bSGordon Ross return (ENOTCONN); 371613a2f6bSGordon Ross 372613a2f6bSGordon Ross /* After reconnect, force close+reopen */ 373613a2f6bSGordon Ross if (sdp->sd_vcgenid != ssp->ss_vcgenid) 374613a2f6bSGordon Ross return (ESTALE); 375613a2f6bSGordon Ross 376613a2f6bSGordon Ross smb_credinit(&scred, cr); 377613a2f6bSGordon Ross ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 378613a2f6bSGordon Ross if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 379613a2f6bSGordon Ross err = EFAULT; 3801b34bc4aSbs goto out; 381613a2f6bSGordon Ross } 382613a2f6bSGordon Ross 383613a2f6bSGordon Ross switch (cmd) { 384613a2f6bSGordon Ross case SMBIOC_READ: 385613a2f6bSGordon Ross rw = UIO_READ; 386613a2f6bSGordon Ross break; 387613a2f6bSGordon Ross case SMBIOC_WRITE: 388613a2f6bSGordon Ross rw = UIO_WRITE; 389613a2f6bSGordon Ross break; 390613a2f6bSGordon Ross default: 391613a2f6bSGordon Ross err = ENODEV; 392613a2f6bSGordon Ross goto out; 393613a2f6bSGordon Ross } 394613a2f6bSGordon Ross 395*430b4c46SGordon Ross /* 396*430b4c46SGordon Ross * If caller passes -1 in ioc_fh, then 397*430b4c46SGordon Ross * use the FID from SMBIOC_NTCREATE. 398*430b4c46SGordon Ross */ 399*430b4c46SGordon Ross if (ioc->ioc_fh == -1) 400*430b4c46SGordon Ross fh = (uint16_t)sdp->sd_smbfid; 401*430b4c46SGordon Ross else 402*430b4c46SGordon Ross fh = (uint16_t)ioc->ioc_fh; 403613a2f6bSGordon Ross 404613a2f6bSGordon Ross aiov[0].iov_base = ioc->ioc_base; 405613a2f6bSGordon Ross aiov[0].iov_len = (size_t)ioc->ioc_cnt; 406613a2f6bSGordon Ross 407613a2f6bSGordon Ross auio.uio_iov = aiov; 408613a2f6bSGordon Ross auio.uio_iovcnt = 1; 409613a2f6bSGordon Ross auio.uio_loffset = ioc->ioc_offset; 410613a2f6bSGordon Ross auio.uio_segflg = (flags & FKIOCTL) ? 411613a2f6bSGordon Ross UIO_SYSSPACE : UIO_USERSPACE; 412613a2f6bSGordon Ross auio.uio_fmode = 0; 413613a2f6bSGordon Ross auio.uio_resid = (size_t)ioc->ioc_cnt; 414613a2f6bSGordon Ross 415613a2f6bSGordon Ross err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0); 416613a2f6bSGordon Ross 417613a2f6bSGordon Ross /* 418613a2f6bSGordon Ross * On return ioc_cnt holds the 419613a2f6bSGordon Ross * number of bytes transferred. 420613a2f6bSGordon Ross */ 421613a2f6bSGordon Ross ioc->ioc_cnt -= auio.uio_resid; 422613a2f6bSGordon Ross 42302d09e03SGordon Ross (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); 424613a2f6bSGordon Ross 4251b34bc4aSbs out: 426*430b4c46SGordon Ross kmem_free(ioc, sizeof (*ioc)); 427*430b4c46SGordon Ross smb_credrele(&scred); 428*430b4c46SGordon Ross 429*430b4c46SGordon Ross return (err); 430*430b4c46SGordon Ross } 431*430b4c46SGordon Ross 432*430b4c46SGordon Ross /* 433*430b4c46SGordon Ross * Helper for nsmb_ioctl case 434*430b4c46SGordon Ross * SMBIOC_NTCREATE 435*430b4c46SGordon Ross */ 436*430b4c46SGordon Ross int 437*430b4c46SGordon Ross smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 438*430b4c46SGordon Ross { 439*430b4c46SGordon Ross struct smb_cred scred; 440*430b4c46SGordon Ross struct mbchain name_mb; 441*430b4c46SGordon Ross struct smb_share *ssp; 442*430b4c46SGordon Ross smbioc_ntcreate_t *ioc = NULL; 443*430b4c46SGordon Ross uint16_t fid; 444*430b4c46SGordon Ross int err, nmlen; 445*430b4c46SGordon Ross 446*430b4c46SGordon Ross /* This ioctl requires a share. */ 447*430b4c46SGordon Ross if ((ssp = sdp->sd_share) == NULL) 448*430b4c46SGordon Ross return (ENOTCONN); 449*430b4c46SGordon Ross 450*430b4c46SGordon Ross /* Must not be already open. */ 451*430b4c46SGordon Ross if (sdp->sd_smbfid != -1) 452*430b4c46SGordon Ross return (EINVAL); 453*430b4c46SGordon Ross 454*430b4c46SGordon Ross mb_init(&name_mb); 455*430b4c46SGordon Ross smb_credinit(&scred, cr); 456*430b4c46SGordon Ross ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 457*430b4c46SGordon Ross if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 458*430b4c46SGordon Ross err = EFAULT; 459*430b4c46SGordon Ross goto out; 460*430b4c46SGordon Ross } 461*430b4c46SGordon Ross 462*430b4c46SGordon Ross /* Build name_mb */ 463*430b4c46SGordon Ross ioc->ioc_name[SMBIOC_MAX_NAME-1] = '\0'; 464*430b4c46SGordon Ross nmlen = strnlen(ioc->ioc_name, SMBIOC_MAX_NAME-1); 465*430b4c46SGordon Ross err = smb_put_dmem(&name_mb, SSTOVC(ssp), 466*430b4c46SGordon Ross ioc->ioc_name, nmlen, 467*430b4c46SGordon Ross SMB_CS_NONE, NULL); 468*430b4c46SGordon Ross if (err != 0) 469*430b4c46SGordon Ross goto out; 470*430b4c46SGordon Ross 471*430b4c46SGordon Ross /* Do the OtW open, save the FID. */ 472*430b4c46SGordon Ross err = smb_smb_ntcreate(ssp, &name_mb, 473*430b4c46SGordon Ross 0, /* create flags */ 474*430b4c46SGordon Ross ioc->ioc_req_acc, 475*430b4c46SGordon Ross ioc->ioc_efattr, 476*430b4c46SGordon Ross ioc->ioc_share_acc, 477*430b4c46SGordon Ross ioc->ioc_open_disp, 478*430b4c46SGordon Ross ioc->ioc_creat_opts, 479*430b4c46SGordon Ross NTCREATEX_IMPERSONATION_IMPERSONATION, 480*430b4c46SGordon Ross &scred, 481*430b4c46SGordon Ross &fid, 482*430b4c46SGordon Ross NULL, 483*430b4c46SGordon Ross NULL); 484*430b4c46SGordon Ross if (err != 0) 485*430b4c46SGordon Ross goto out; 486*430b4c46SGordon Ross 487*430b4c46SGordon Ross sdp->sd_smbfid = fid; 488*430b4c46SGordon Ross sdp->sd_vcgenid = ssp->ss_vcgenid; 489*430b4c46SGordon Ross 490*430b4c46SGordon Ross out: 491*430b4c46SGordon Ross kmem_free(ioc, sizeof (*ioc)); 492*430b4c46SGordon Ross smb_credrele(&scred); 493*430b4c46SGordon Ross mb_done(&name_mb); 494*430b4c46SGordon Ross 495*430b4c46SGordon Ross return (err); 496*430b4c46SGordon Ross } 497*430b4c46SGordon Ross 498*430b4c46SGordon Ross /* 499*430b4c46SGordon Ross * Helper for nsmb_ioctl case 500*430b4c46SGordon Ross * SMBIOC_PRINTJOB 501*430b4c46SGordon Ross */ 502*430b4c46SGordon Ross int 503*430b4c46SGordon Ross smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 504*430b4c46SGordon Ross { 505*430b4c46SGordon Ross struct smb_cred scred; 506*430b4c46SGordon Ross struct smb_share *ssp; 507*430b4c46SGordon Ross smbioc_printjob_t *ioc = NULL; 508*430b4c46SGordon Ross uint16_t fid; 509*430b4c46SGordon Ross int err; 510*430b4c46SGordon Ross 511*430b4c46SGordon Ross /* This ioctl requires a share. */ 512*430b4c46SGordon Ross if ((ssp = sdp->sd_share) == NULL) 513*430b4c46SGordon Ross return (ENOTCONN); 514*430b4c46SGordon Ross 515*430b4c46SGordon Ross /* The share must be a print queue. */ 516*430b4c46SGordon Ross if (ssp->ss_type != STYPE_PRINTQ) 517*430b4c46SGordon Ross return (EINVAL); 518*430b4c46SGordon Ross 519*430b4c46SGordon Ross /* Must not be already open. */ 520*430b4c46SGordon Ross if (sdp->sd_smbfid != -1) 521*430b4c46SGordon Ross return (EINVAL); 522*430b4c46SGordon Ross 523*430b4c46SGordon Ross smb_credinit(&scred, cr); 524*430b4c46SGordon Ross ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 525*430b4c46SGordon Ross if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 526*430b4c46SGordon Ross err = EFAULT; 527*430b4c46SGordon Ross goto out; 528*430b4c46SGordon Ross } 529*430b4c46SGordon Ross ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0'; 530*430b4c46SGordon Ross 531*430b4c46SGordon Ross /* Do the OtW open, save the FID. */ 532*430b4c46SGordon Ross err = smb_smb_open_prjob(ssp, ioc->ioc_title, 533*430b4c46SGordon Ross ioc->ioc_setuplen, ioc->ioc_prmode, 534*430b4c46SGordon Ross &scred, &fid); 535*430b4c46SGordon Ross if (err != 0) 536*430b4c46SGordon Ross goto out; 537*430b4c46SGordon Ross 538*430b4c46SGordon Ross sdp->sd_smbfid = fid; 539*430b4c46SGordon Ross sdp->sd_vcgenid = ssp->ss_vcgenid; 540*430b4c46SGordon Ross 541*430b4c46SGordon Ross out: 542*430b4c46SGordon Ross kmem_free(ioc, sizeof (*ioc)); 543*430b4c46SGordon Ross smb_credrele(&scred); 544*430b4c46SGordon Ross 545*430b4c46SGordon Ross return (err); 546*430b4c46SGordon Ross } 547*430b4c46SGordon Ross 548*430b4c46SGordon Ross /* 549*430b4c46SGordon Ross * Helper for nsmb_ioctl case 550*430b4c46SGordon Ross * SMBIOC_CLOSEFH 551*430b4c46SGordon Ross */ 552*430b4c46SGordon Ross int 553*430b4c46SGordon Ross smb_usr_closefh(smb_dev_t *sdp, cred_t *cr) 554*430b4c46SGordon Ross { 555*430b4c46SGordon Ross struct smb_cred scred; 556*430b4c46SGordon Ross struct smb_share *ssp; 557*430b4c46SGordon Ross uint16_t fid; 558*430b4c46SGordon Ross int err; 559*430b4c46SGordon Ross 560*430b4c46SGordon Ross /* This ioctl requires a share. */ 561*430b4c46SGordon Ross if ((ssp = sdp->sd_share) == NULL) 562*430b4c46SGordon Ross return (ENOTCONN); 563*430b4c46SGordon Ross 564*430b4c46SGordon Ross if (sdp->sd_smbfid == -1) 565*430b4c46SGordon Ross return (0); 566*430b4c46SGordon Ross fid = (uint16_t)sdp->sd_smbfid; 567*430b4c46SGordon Ross sdp->sd_smbfid = -1; 568*430b4c46SGordon Ross 569*430b4c46SGordon Ross smb_credinit(&scred, cr); 570*430b4c46SGordon Ross if (ssp->ss_type == STYPE_PRINTQ) 571*430b4c46SGordon Ross err = smb_smb_close_prjob(ssp, fid, &scred); 572*430b4c46SGordon Ross else 573*430b4c46SGordon Ross err = smb_smb_close(ssp, fid, NULL, &scred); 574613a2f6bSGordon Ross smb_credrele(&scred); 575613a2f6bSGordon Ross 576613a2f6bSGordon Ross return (err); 5771b34bc4aSbs } 5781b34bc4aSbs 579613a2f6bSGordon Ross /* 580613a2f6bSGordon Ross * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE 581613a2f6bSGordon Ross * Find or create a session (a.k.a. "VC" in here) 582613a2f6bSGordon Ross */ 5834bff34e3Sthurlow int 584613a2f6bSGordon Ross smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 5854bff34e3Sthurlow { 586613a2f6bSGordon Ross struct smb_cred scred; 587613a2f6bSGordon Ross smbioc_ossn_t *ossn = NULL; 5884bff34e3Sthurlow struct smb_vc *vcp = NULL; 5894bff34e3Sthurlow int error = 0; 590613a2f6bSGordon Ross uid_t realuid; 5914bff34e3Sthurlow 592613a2f6bSGordon Ross /* Should be no VC */ 593613a2f6bSGordon Ross if (sdp->sd_vc != NULL) 594613a2f6bSGordon Ross return (EISCONN); 595613a2f6bSGordon Ross 596613a2f6bSGordon Ross smb_credinit(&scred, cr); 597613a2f6bSGordon Ross ossn = kmem_alloc(sizeof (*ossn), KM_SLEEP); 598613a2f6bSGordon Ross if (ddi_copyin((void *)arg, ossn, sizeof (*ossn), flags)) { 599613a2f6bSGordon Ross error = EFAULT; 600613a2f6bSGordon Ross goto out; 6014bff34e3Sthurlow } 602613a2f6bSGordon Ross 603613a2f6bSGordon Ross /* 604613a2f6bSGordon Ross * Only superuser can specify a UID or GID. 605613a2f6bSGordon Ross */ 606613a2f6bSGordon Ross realuid = crgetruid(cr); 607613a2f6bSGordon Ross if (ossn->ssn_owner == SMBM_ANY_OWNER) 608613a2f6bSGordon Ross ossn->ssn_owner = realuid; 609613a2f6bSGordon Ross else { 6104bff34e3Sthurlow /* 611613a2f6bSGordon Ross * Do we have the privilege to create with the 612613a2f6bSGordon Ross * specified uid? (does uid == cr->cr_uid, etc.) 6134bff34e3Sthurlow */ 614613a2f6bSGordon Ross if (secpolicy_vnode_owner(cr, ossn->ssn_owner)) { 615613a2f6bSGordon Ross error = EPERM; 616613a2f6bSGordon Ross goto out; 6174bff34e3Sthurlow } 618613a2f6bSGordon Ross /* ossn->ssn_owner is OK */ 6194bff34e3Sthurlow } 6204bff34e3Sthurlow 621613a2f6bSGordon Ross /* 622613a2f6bSGordon Ross * Make sure the strings are null terminated. 623613a2f6bSGordon Ross */ 624613a2f6bSGordon Ross ossn->ssn_srvname[SMBIOC_MAX_NAME-1] = '\0'; 625613a2f6bSGordon Ross ossn->ssn_id.id_domain[ SMBIOC_MAX_NAME-1] = '\0'; 626613a2f6bSGordon Ross ossn->ssn_id.id_user[ SMBIOC_MAX_NAME-1] = '\0'; 6274bff34e3Sthurlow 628613a2f6bSGordon Ross if (cmd == SMBIOC_SSN_CREATE) 629613a2f6bSGordon Ross ossn->ssn_vopt |= SMBVOPT_CREATE; 630613a2f6bSGordon Ross else /* FIND */ 631613a2f6bSGordon Ross ossn->ssn_vopt &= ~SMBVOPT_CREATE; 6324bff34e3Sthurlow 633613a2f6bSGordon Ross error = smb_vc_findcreate(ossn, &scred, &vcp); 6344bff34e3Sthurlow if (error) 6354bff34e3Sthurlow goto out; 636613a2f6bSGordon Ross ASSERT(vcp != NULL); 6374bff34e3Sthurlow 6384bff34e3Sthurlow /* 639613a2f6bSGordon Ross * We have a VC, held, but not locked. 640613a2f6bSGordon Ross * If we're creating, mark this instance as 641613a2f6bSGordon Ross * an open from IOD so close can do cleanup. 642613a2f6bSGordon Ross * 643613a2f6bSGordon Ross * XXX: Would be nice to have a back pointer 644613a2f6bSGordon Ross * from the VC to this (IOD) sdp instance. 6454bff34e3Sthurlow */ 646613a2f6bSGordon Ross if (cmd == SMBIOC_SSN_CREATE) { 647613a2f6bSGordon Ross if (vcp->iod_thr != NULL) { 648613a2f6bSGordon Ross error = EEXIST; 649613a2f6bSGordon Ross goto out; 650613a2f6bSGordon Ross } 651613a2f6bSGordon Ross sdp->sd_flags |= NSMBFL_IOD; 652613a2f6bSGordon Ross } else { 653613a2f6bSGordon Ross /* 654613a2f6bSGordon Ross * Wait for it to finish connecting 655613a2f6bSGordon Ross * (or reconnect) if necessary. 656613a2f6bSGordon Ross */ 657613a2f6bSGordon Ross if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { 658613a2f6bSGordon Ross error = smb_iod_reconnect(vcp); 659613a2f6bSGordon Ross if (error != 0) 660613a2f6bSGordon Ross goto out; 661613a2f6bSGordon Ross } 662613a2f6bSGordon Ross } 663613a2f6bSGordon Ross 664613a2f6bSGordon Ross /* 665613a2f6bSGordon Ross * The VC has a hold from _findvc 666613a2f6bSGordon Ross * which we keep until _SSN_RELE 667613a2f6bSGordon Ross * or nsmb_close(). 668613a2f6bSGordon Ross */ 669613a2f6bSGordon Ross sdp->sd_level = SMBL_VC; 670613a2f6bSGordon Ross sdp->sd_vc = vcp; 671613a2f6bSGordon Ross vcp = NULL; 672613a2f6bSGordon Ross (void) ddi_copyout(ossn, (void *)arg, sizeof (*ossn), flags); 6734bff34e3Sthurlow 6744bff34e3Sthurlow out: 675613a2f6bSGordon Ross if (vcp) { 676613a2f6bSGordon Ross /* Error path: rele hold from _findcreate */ 677613a2f6bSGordon Ross smb_vc_rele(vcp); 678613a2f6bSGordon Ross } 679*430b4c46SGordon Ross kmem_free(ossn, sizeof (*ossn)); 680613a2f6bSGordon Ross smb_credrele(&scred); 681613a2f6bSGordon Ross 6824bff34e3Sthurlow return (error); 6834bff34e3Sthurlow } 6844bff34e3Sthurlow 685613a2f6bSGordon Ross /* 686613a2f6bSGordon Ross * Ioctl functions: SMBIOC_SSN_RELE, SMBIOC_SSN_KILL 687613a2f6bSGordon Ross * Release or kill the current session. 688613a2f6bSGordon Ross */ 6894bff34e3Sthurlow int 690613a2f6bSGordon Ross smb_usr_drop_ssn(smb_dev_t *sdp, int cmd) 6914bff34e3Sthurlow { 692613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 6934bff34e3Sthurlow 694613a2f6bSGordon Ross /* Must have a VC. */ 695613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 696613a2f6bSGordon Ross return (ENOTCONN); 6974bff34e3Sthurlow 698613a2f6bSGordon Ross /* If we have a share ref, drop it too. */ 699613a2f6bSGordon Ross if (sdp->sd_share) { 700613a2f6bSGordon Ross smb_share_rele(sdp->sd_share); 701613a2f6bSGordon Ross sdp->sd_share = NULL; 702613a2f6bSGordon Ross sdp->sd_level = SMBL_VC; 7034bff34e3Sthurlow } 7044bff34e3Sthurlow 705613a2f6bSGordon Ross if (cmd == SMBIOC_SSN_KILL) 706613a2f6bSGordon Ross smb_vc_kill(vcp); 7074bff34e3Sthurlow 708613a2f6bSGordon Ross /* Drop the VC ref. */ 709613a2f6bSGordon Ross smb_vc_rele(vcp); 710613a2f6bSGordon Ross sdp->sd_vc = NULL; 711613a2f6bSGordon Ross sdp->sd_level = 0; 712613a2f6bSGordon Ross 713613a2f6bSGordon Ross return (0); 7144bff34e3Sthurlow } 7154bff34e3Sthurlow 7164bff34e3Sthurlow /* 717613a2f6bSGordon Ross * Find or create a tree (connected share) 7184bff34e3Sthurlow */ 7194bff34e3Sthurlow int 720613a2f6bSGordon Ross smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 7214bff34e3Sthurlow { 722613a2f6bSGordon Ross struct smb_cred scred; 723613a2f6bSGordon Ross smbioc_tcon_t *tcon = NULL; 724613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 725613a2f6bSGordon Ross struct smb_share *ssp = NULL; 726613a2f6bSGordon Ross int error = 0; 7274bff34e3Sthurlow 728613a2f6bSGordon Ross /* Must have a VC. */ 729613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 730613a2f6bSGordon Ross return (ENOTCONN); 731613a2f6bSGordon Ross /* Should not have a share. */ 732613a2f6bSGordon Ross if (sdp->sd_share != NULL) 733613a2f6bSGordon Ross return (EISCONN); 734613a2f6bSGordon Ross 735613a2f6bSGordon Ross smb_credinit(&scred, cr); 736613a2f6bSGordon Ross tcon = kmem_alloc(sizeof (*tcon), KM_SLEEP); 737613a2f6bSGordon Ross if (ddi_copyin((void *)arg, tcon, sizeof (*tcon), flags)) { 738613a2f6bSGordon Ross error = EFAULT; 739613a2f6bSGordon Ross goto out; 7404bff34e3Sthurlow } 741613a2f6bSGordon Ross 742613a2f6bSGordon Ross /* 743613a2f6bSGordon Ross * Make sure the strings are null terminated. 744613a2f6bSGordon Ross */ 745613a2f6bSGordon Ross tcon->tc_sh.sh_name[SMBIOC_MAX_NAME-1] = '\0'; 746613a2f6bSGordon Ross tcon->tc_sh.sh_pass[SMBIOC_MAX_NAME-1] = '\0'; 747613a2f6bSGordon Ross 748613a2f6bSGordon Ross if (cmd == SMBIOC_TREE_CONNECT) 749613a2f6bSGordon Ross tcon->tc_opt |= SMBSOPT_CREATE; 750613a2f6bSGordon Ross else /* FIND */ 751613a2f6bSGordon Ross tcon->tc_opt &= ~SMBSOPT_CREATE; 752613a2f6bSGordon Ross 753613a2f6bSGordon Ross error = smb_share_findcreate(tcon, vcp, &ssp, &scred); 7544bff34e3Sthurlow if (error) 755613a2f6bSGordon Ross goto out; 756613a2f6bSGordon Ross ASSERT(ssp != NULL); 757613a2f6bSGordon Ross 758613a2f6bSGordon Ross /* 759613a2f6bSGordon Ross * We have a share, held, but not locked. 760613a2f6bSGordon Ross * If we're creating, do tree connect now, 761613a2f6bSGordon Ross * otherwise let that wait for a request. 762613a2f6bSGordon Ross */ 763613a2f6bSGordon Ross if (cmd == SMBIOC_TREE_CONNECT) { 764613a2f6bSGordon Ross error = smb_share_tcon(ssp, &scred); 765613a2f6bSGordon Ross if (error) 766613a2f6bSGordon Ross goto out; 7674bff34e3Sthurlow } 768613a2f6bSGordon Ross 769613a2f6bSGordon Ross /* 770613a2f6bSGordon Ross * Give caller the real share type from 771613a2f6bSGordon Ross * the tree connect response, so they can 772613a2f6bSGordon Ross * see if they got the requested type. 773613a2f6bSGordon Ross */ 774*430b4c46SGordon Ross tcon->tc_sh.sh_type = ssp->ss_type; 775613a2f6bSGordon Ross 776613a2f6bSGordon Ross /* 777613a2f6bSGordon Ross * The share has a hold from _tcon 778613a2f6bSGordon Ross * which we keep until nsmb_close() 779613a2f6bSGordon Ross * or the SMBIOC_TDIS below. 780613a2f6bSGordon Ross */ 781613a2f6bSGordon Ross sdp->sd_level = SMBL_SHARE; 782613a2f6bSGordon Ross sdp->sd_share = ssp; 783613a2f6bSGordon Ross ssp = NULL; 784613a2f6bSGordon Ross (void) ddi_copyout(tcon, (void *)arg, sizeof (*tcon), flags); 785613a2f6bSGordon Ross 786613a2f6bSGordon Ross out: 787613a2f6bSGordon Ross if (ssp) { 788613a2f6bSGordon Ross /* Error path: rele hold from _findcreate */ 789613a2f6bSGordon Ross smb_share_rele(ssp); 7904bff34e3Sthurlow } 791*430b4c46SGordon Ross /* 792*430b4c46SGordon Ross * This structure may contain a 793*430b4c46SGordon Ross * cleartext password, so zap it. 794*430b4c46SGordon Ross */ 795*430b4c46SGordon Ross bzero(tcon, sizeof (*tcon)); 796*430b4c46SGordon Ross kmem_free(tcon, sizeof (*tcon)); 797613a2f6bSGordon Ross smb_credrele(&scred); 7984bff34e3Sthurlow 799613a2f6bSGordon Ross return (error); 8004bff34e3Sthurlow } 8014bff34e3Sthurlow 802613a2f6bSGordon Ross /* 803613a2f6bSGordon Ross * Ioctl functions: SMBIOC_TREE_RELE, SMBIOC_TREE_KILL 804613a2f6bSGordon Ross * Release or kill the current tree 805613a2f6bSGordon Ross */ 806613a2f6bSGordon Ross int 807613a2f6bSGordon Ross smb_usr_drop_tree(smb_dev_t *sdp, int cmd) 8084bff34e3Sthurlow { 809613a2f6bSGordon Ross struct smb_share *ssp = NULL; 8104bff34e3Sthurlow 811613a2f6bSGordon Ross /* Must have a VC and a share. */ 812613a2f6bSGordon Ross if (sdp->sd_vc == NULL) 813613a2f6bSGordon Ross return (ENOTCONN); 814613a2f6bSGordon Ross if ((ssp = sdp->sd_share) == NULL) 815613a2f6bSGordon Ross return (ENOTCONN); 816613a2f6bSGordon Ross 817613a2f6bSGordon Ross if (cmd == SMBIOC_TREE_KILL) 818613a2f6bSGordon Ross smb_share_kill(ssp); 819613a2f6bSGordon Ross 820613a2f6bSGordon Ross /* Drop the share ref. */ 821613a2f6bSGordon Ross smb_share_rele(sdp->sd_share); 822613a2f6bSGordon Ross sdp->sd_share = NULL; 823613a2f6bSGordon Ross sdp->sd_level = SMBL_VC; 824613a2f6bSGordon Ross 825613a2f6bSGordon Ross return (0); 8264bff34e3Sthurlow } 8274bff34e3Sthurlow 828613a2f6bSGordon Ross 829613a2f6bSGordon Ross /* 830613a2f6bSGordon Ross * Ioctl function: SMBIOC_IOD_WORK 831613a2f6bSGordon Ross * 832613a2f6bSGordon Ross * Become the reader (IOD) thread, until either the connection is 833613a2f6bSGordon Ross * reset by the server, or until the connection is idle longer than 834613a2f6bSGordon Ross * some max time. (max idle time not yet implemented) 835613a2f6bSGordon Ross */ 8364bff34e3Sthurlow int 837613a2f6bSGordon Ross smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 8384bff34e3Sthurlow { 839613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 840613a2f6bSGordon Ross int err = 0; 8414bff34e3Sthurlow 842613a2f6bSGordon Ross /* Must have a valid session. */ 843613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 8444bff34e3Sthurlow return (EINVAL); 845613a2f6bSGordon Ross if (vcp->vc_flags & SMBV_GONE) 846613a2f6bSGordon Ross return (EINVAL); 847613a2f6bSGordon Ross 848613a2f6bSGordon Ross /* 849613a2f6bSGordon Ross * Is there already an IOD for this VC? 850613a2f6bSGordon Ross * (Should never happen.) 851613a2f6bSGordon Ross */ 852613a2f6bSGordon Ross SMB_VC_LOCK(vcp); 853613a2f6bSGordon Ross if (vcp->iod_thr == NULL) 854613a2f6bSGordon Ross vcp->iod_thr = curthread; 855613a2f6bSGordon Ross else 856613a2f6bSGordon Ross err = EEXIST; 857613a2f6bSGordon Ross SMB_VC_UNLOCK(vcp); 858613a2f6bSGordon Ross if (err) 859613a2f6bSGordon Ross return (err); 860613a2f6bSGordon Ross 861613a2f6bSGordon Ross /* 862613a2f6bSGordon Ross * Copy the "work" state, etc. into the VC 863613a2f6bSGordon Ross * The MAC key is copied separately. 864613a2f6bSGordon Ross */ 865613a2f6bSGordon Ross if (ddi_copyin((void *)arg, &vcp->vc_work, 866613a2f6bSGordon Ross sizeof (smbioc_ssn_work_t), flags)) { 867613a2f6bSGordon Ross err = EFAULT; 868613a2f6bSGordon Ross goto out; 8694bff34e3Sthurlow } 870613a2f6bSGordon Ross if (vcp->vc_u_maclen) { 871613a2f6bSGordon Ross vcp->vc_mackeylen = vcp->vc_u_maclen; 872613a2f6bSGordon Ross vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP); 873613a2f6bSGordon Ross if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey, 874613a2f6bSGordon Ross vcp->vc_mackeylen, flags)) { 875613a2f6bSGordon Ross err = EFAULT; 876613a2f6bSGordon Ross goto out; 8774bff34e3Sthurlow } 8789c9af259SGordon Ross } 879613a2f6bSGordon Ross 880613a2f6bSGordon Ross err = smb_iod_vc_work(vcp, cr); 881613a2f6bSGordon Ross 882613a2f6bSGordon Ross /* Caller wants state here. */ 883613a2f6bSGordon Ross vcp->vc_work.wk_out_state = vcp->vc_state; 884613a2f6bSGordon Ross 885613a2f6bSGordon Ross (void) ddi_copyout(&vcp->vc_work, (void *)arg, 886613a2f6bSGordon Ross sizeof (smbioc_ssn_work_t), flags); 887613a2f6bSGordon Ross 888613a2f6bSGordon Ross out: 889613a2f6bSGordon Ross if (vcp->vc_mackey) { 890613a2f6bSGordon Ross kmem_free(vcp->vc_mackey, vcp->vc_mackeylen); 891613a2f6bSGordon Ross vcp->vc_mackey = NULL; 892613a2f6bSGordon Ross vcp->vc_mackeylen = 0; 893613a2f6bSGordon Ross } 894613a2f6bSGordon Ross 895613a2f6bSGordon Ross /* 896613a2f6bSGordon Ross * The IOD thread is leaving the driver. Clear iod_thr, 897613a2f6bSGordon Ross * and wake up anybody waiting for us to quit. 898613a2f6bSGordon Ross */ 899613a2f6bSGordon Ross SMB_VC_LOCK(vcp); 900613a2f6bSGordon Ross vcp->iod_thr = NULL; 901613a2f6bSGordon Ross cv_broadcast(&vcp->vc_statechg); 902613a2f6bSGordon Ross SMB_VC_UNLOCK(vcp); 903613a2f6bSGordon Ross 904613a2f6bSGordon Ross return (err); 9054bff34e3Sthurlow } 9064bff34e3Sthurlow 9074bff34e3Sthurlow /* 908613a2f6bSGordon Ross * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL 909613a2f6bSGordon Ross * 910613a2f6bSGordon Ross * Wait for user-level requests to be enqueued on this session, 911613a2f6bSGordon Ross * and then return to the user-space helper, which will then 912613a2f6bSGordon Ross * initiate a reconnect, etc. 9134bff34e3Sthurlow */ 9144bff34e3Sthurlow int 915613a2f6bSGordon Ross smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags) 9164bff34e3Sthurlow { 917613a2f6bSGordon Ross struct smb_vc *vcp = NULL; 918613a2f6bSGordon Ross int err = 0; 919613a2f6bSGordon Ross 920613a2f6bSGordon Ross /* Must have a valid session. */ 921613a2f6bSGordon Ross if ((vcp = sdp->sd_vc) == NULL) 922613a2f6bSGordon Ross return (EINVAL); 923613a2f6bSGordon Ross if (vcp->vc_flags & SMBV_GONE) 924613a2f6bSGordon Ross return (EINVAL); 925613a2f6bSGordon Ross 926613a2f6bSGordon Ross /* 927613a2f6bSGordon Ross * Is there already an IOD for this VC? 928613a2f6bSGordon Ross * (Should never happen.) 929613a2f6bSGordon Ross */ 930613a2f6bSGordon Ross SMB_VC_LOCK(vcp); 931613a2f6bSGordon Ross if (vcp->iod_thr == NULL) 932613a2f6bSGordon Ross vcp->iod_thr = curthread; 933613a2f6bSGordon Ross else 934613a2f6bSGordon Ross err = EEXIST; 935613a2f6bSGordon Ross SMB_VC_UNLOCK(vcp); 936613a2f6bSGordon Ross if (err) 937613a2f6bSGordon Ross return (err); 938613a2f6bSGordon Ross 939613a2f6bSGordon Ross /* nothing to copyin */ 9404bff34e3Sthurlow 9414bff34e3Sthurlow switch (cmd) { 942613a2f6bSGordon Ross case SMBIOC_IOD_IDLE: 943613a2f6bSGordon Ross err = smb_iod_vc_idle(vcp); 9444bff34e3Sthurlow break; 945613a2f6bSGordon Ross 946613a2f6bSGordon Ross case SMBIOC_IOD_RCFAIL: 947613a2f6bSGordon Ross err = smb_iod_vc_rcfail(vcp); 9484bff34e3Sthurlow break; 949613a2f6bSGordon Ross 9504bff34e3Sthurlow default: 951613a2f6bSGordon Ross err = ENOTTY; 952613a2f6bSGordon Ross goto out; 9534bff34e3Sthurlow } 9544bff34e3Sthurlow 955613a2f6bSGordon Ross /* Both of these ioctls copy out the new state. */ 956613a2f6bSGordon Ross (void) ddi_copyout(&vcp->vc_state, (void *)arg, 957613a2f6bSGordon Ross sizeof (int), flags); 9584bff34e3Sthurlow 959613a2f6bSGordon Ross out: 9604bff34e3Sthurlow /* 961613a2f6bSGordon Ross * The IOD thread is leaving the driver. Clear iod_thr, 962613a2f6bSGordon Ross * and wake up anybody waiting for us to quit. 9634bff34e3Sthurlow */ 964613a2f6bSGordon Ross SMB_VC_LOCK(vcp); 965613a2f6bSGordon Ross vcp->iod_thr = NULL; 966613a2f6bSGordon Ross cv_broadcast(&vcp->vc_statechg); 967613a2f6bSGordon Ross SMB_VC_UNLOCK(vcp); 9684bff34e3Sthurlow 969613a2f6bSGordon Ross return (err); 9704bff34e3Sthurlow } 971