1c398230bSWarner Losh /*- 2681a5bbeSBoris Popov * Copyright (c) 2000-2001 Boris Popov 3681a5bbeSBoris Popov * All rights reserved. 4681a5bbeSBoris Popov * 5681a5bbeSBoris Popov * Redistribution and use in source and binary forms, with or without 6681a5bbeSBoris Popov * modification, are permitted provided that the following conditions 7681a5bbeSBoris Popov * are met: 8681a5bbeSBoris Popov * 1. Redistributions of source code must retain the above copyright 9681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer. 10681a5bbeSBoris Popov * 2. Redistributions in binary form must reproduce the above copyright 11681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer in the 12681a5bbeSBoris Popov * documentation and/or other materials provided with the distribution. 13681a5bbeSBoris Popov * 3. All advertising materials mentioning features or use of this software 14681a5bbeSBoris Popov * must display the following acknowledgement: 15681a5bbeSBoris Popov * This product includes software developed by Boris Popov. 16681a5bbeSBoris Popov * 4. Neither the name of the author nor the names of any co-contributors 17681a5bbeSBoris Popov * may be used to endorse or promote products derived from this software 18681a5bbeSBoris Popov * without specific prior written permission. 19681a5bbeSBoris Popov * 20681a5bbeSBoris Popov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21681a5bbeSBoris Popov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22681a5bbeSBoris Popov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23681a5bbeSBoris Popov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24681a5bbeSBoris Popov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25681a5bbeSBoris Popov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26681a5bbeSBoris Popov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27681a5bbeSBoris Popov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28681a5bbeSBoris Popov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29681a5bbeSBoris Popov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30681a5bbeSBoris Popov * SUCH DAMAGE. 31681a5bbeSBoris Popov */ 32ab0de15bSDavid E. O'Brien 33ab0de15bSDavid E. O'Brien #include <sys/cdefs.h> 34ab0de15bSDavid E. O'Brien __FBSDID("$FreeBSD$"); 35ab0de15bSDavid E. O'Brien 36681a5bbeSBoris Popov #include <sys/param.h> 37681a5bbeSBoris Popov #include <sys/malloc.h> 38681a5bbeSBoris Popov #include <sys/kernel.h> 39681a5bbeSBoris Popov #include <sys/systm.h> 40681a5bbeSBoris Popov #include <sys/conf.h> 41681a5bbeSBoris Popov #include <sys/proc.h> 42681a5bbeSBoris Popov #include <sys/fcntl.h> 43681a5bbeSBoris Popov #include <sys/socket.h> 44681a5bbeSBoris Popov #include <sys/socketvar.h> 45681a5bbeSBoris Popov #include <sys/sysctl.h> 469f86067aSPoul-Henning Kamp #include <sys/mbuf.h> 47681a5bbeSBoris Popov 48681a5bbeSBoris Popov #include <sys/iconv.h> 49681a5bbeSBoris Popov 50681a5bbeSBoris Popov #include <netsmb/smb.h> 51681a5bbeSBoris Popov #include <netsmb/smb_conn.h> 52681a5bbeSBoris Popov #include <netsmb/smb_rq.h> 53681a5bbeSBoris Popov #include <netsmb/smb_subr.h> 54681a5bbeSBoris Popov #include <netsmb/smb_dev.h> 55681a5bbeSBoris Popov 56681a5bbeSBoris Popov /* 57681a5bbeSBoris Popov * helpers for nsmb device. Can be moved to the smb_dev.c file. 58681a5bbeSBoris Popov */ 59681a5bbeSBoris Popov static void smb_usr_vcspec_free(struct smb_vcspec *spec); 60681a5bbeSBoris Popov 61681a5bbeSBoris Popov static int 62681a5bbeSBoris Popov smb_usr_vc2spec(struct smbioc_ossn *dp, struct smb_vcspec *spec) 63681a5bbeSBoris Popov { 64681a5bbeSBoris Popov int flags = 0; 65681a5bbeSBoris Popov 66681a5bbeSBoris Popov bzero(spec, sizeof(*spec)); 67994ad180SBoris Popov 68994ad180SBoris Popov #ifdef NETSMB_NO_ANON_USER 69681a5bbeSBoris Popov if (dp->ioc_user[0] == 0) 70681a5bbeSBoris Popov return EINVAL; 71994ad180SBoris Popov #endif 72994ad180SBoris Popov 73681a5bbeSBoris Popov if (dp->ioc_server == NULL) 74681a5bbeSBoris Popov return EINVAL; 75681a5bbeSBoris Popov if (dp->ioc_localcs[0] == 0) { 76681a5bbeSBoris Popov SMBERROR("no local charset ?\n"); 77681a5bbeSBoris Popov return EINVAL; 78681a5bbeSBoris Popov } 79681a5bbeSBoris Popov 80681a5bbeSBoris Popov spec->sap = smb_memdupin(dp->ioc_server, dp->ioc_svlen); 81681a5bbeSBoris Popov if (spec->sap == NULL) 82681a5bbeSBoris Popov return ENOMEM; 83681a5bbeSBoris Popov if (dp->ioc_local) { 84681a5bbeSBoris Popov spec->lap = smb_memdupin(dp->ioc_local, dp->ioc_lolen); 85681a5bbeSBoris Popov if (spec->lap == NULL) { 86681a5bbeSBoris Popov smb_usr_vcspec_free(spec); 87681a5bbeSBoris Popov return ENOMEM; 88681a5bbeSBoris Popov } 89681a5bbeSBoris Popov } 90681a5bbeSBoris Popov spec->srvname = dp->ioc_srvname; 91681a5bbeSBoris Popov spec->pass = dp->ioc_password; 92681a5bbeSBoris Popov spec->domain = dp->ioc_workgroup; 93681a5bbeSBoris Popov spec->username = dp->ioc_user; 94681a5bbeSBoris Popov spec->mode = dp->ioc_mode; 95681a5bbeSBoris Popov spec->rights = dp->ioc_rights; 96681a5bbeSBoris Popov spec->owner = dp->ioc_owner; 97681a5bbeSBoris Popov spec->group = dp->ioc_group; 98681a5bbeSBoris Popov spec->localcs = dp->ioc_localcs; 99681a5bbeSBoris Popov spec->servercs = dp->ioc_servercs; 100681a5bbeSBoris Popov if (dp->ioc_opt & SMBVOPT_PRIVATE) 101681a5bbeSBoris Popov flags |= SMBV_PRIVATE; 102681a5bbeSBoris Popov if (dp->ioc_opt & SMBVOPT_SINGLESHARE) 103681a5bbeSBoris Popov flags |= SMBV_PRIVATE | SMBV_SINGLESHARE; 104681a5bbeSBoris Popov spec->flags = flags; 105681a5bbeSBoris Popov return 0; 106681a5bbeSBoris Popov } 107681a5bbeSBoris Popov 108681a5bbeSBoris Popov static void 109681a5bbeSBoris Popov smb_usr_vcspec_free(struct smb_vcspec *spec) 110681a5bbeSBoris Popov { 111681a5bbeSBoris Popov if (spec->sap) 112681a5bbeSBoris Popov smb_memfree(spec->sap); 113681a5bbeSBoris Popov if (spec->lap) 114681a5bbeSBoris Popov smb_memfree(spec->lap); 115681a5bbeSBoris Popov } 116681a5bbeSBoris Popov 117681a5bbeSBoris Popov static int 118681a5bbeSBoris Popov smb_usr_share2spec(struct smbioc_oshare *dp, struct smb_sharespec *spec) 119681a5bbeSBoris Popov { 120681a5bbeSBoris Popov bzero(spec, sizeof(*spec)); 121681a5bbeSBoris Popov spec->mode = dp->ioc_mode; 122681a5bbeSBoris Popov spec->rights = dp->ioc_rights; 123681a5bbeSBoris Popov spec->owner = dp->ioc_owner; 124681a5bbeSBoris Popov spec->group = dp->ioc_group; 125681a5bbeSBoris Popov spec->name = dp->ioc_share; 126681a5bbeSBoris Popov spec->stype = dp->ioc_stype; 127681a5bbeSBoris Popov spec->pass = dp->ioc_password; 128681a5bbeSBoris Popov return 0; 129681a5bbeSBoris Popov } 130681a5bbeSBoris Popov 131681a5bbeSBoris Popov int 132681a5bbeSBoris Popov smb_usr_lookup(struct smbioc_lookup *dp, struct smb_cred *scred, 133681a5bbeSBoris Popov struct smb_vc **vcpp, struct smb_share **sspp) 134681a5bbeSBoris Popov { 135681a5bbeSBoris Popov struct smb_vc *vcp = NULL; 136681a5bbeSBoris Popov struct smb_vcspec vspec; 137681a5bbeSBoris Popov struct smb_sharespec sspec, *sspecp = NULL; 138681a5bbeSBoris Popov int error; 139681a5bbeSBoris Popov 140681a5bbeSBoris Popov if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE) 141681a5bbeSBoris Popov return EINVAL; 142681a5bbeSBoris Popov error = smb_usr_vc2spec(&dp->ioc_ssn, &vspec); 143681a5bbeSBoris Popov if (error) 144681a5bbeSBoris Popov return error; 145681a5bbeSBoris Popov if (dp->ioc_flags & SMBLK_CREATE) 146681a5bbeSBoris Popov vspec.flags |= SMBV_CREATE; 147681a5bbeSBoris Popov 148681a5bbeSBoris Popov if (dp->ioc_level >= SMBL_SHARE) { 149681a5bbeSBoris Popov error = smb_usr_share2spec(&dp->ioc_sh, &sspec); 150681a5bbeSBoris Popov if (error) 151681a5bbeSBoris Popov goto out; 152681a5bbeSBoris Popov sspecp = &sspec; 153681a5bbeSBoris Popov } 154681a5bbeSBoris Popov error = smb_sm_lookup(&vspec, sspecp, scred, &vcp); 155681a5bbeSBoris Popov if (error == 0) { 156681a5bbeSBoris Popov *vcpp = vcp; 157681a5bbeSBoris Popov *sspp = vspec.ssp; 158681a5bbeSBoris Popov } 159681a5bbeSBoris Popov out: 160681a5bbeSBoris Popov smb_usr_vcspec_free(&vspec); 161681a5bbeSBoris Popov return error; 162681a5bbeSBoris Popov } 163681a5bbeSBoris Popov 164681a5bbeSBoris Popov /* 165681a5bbeSBoris Popov * Connect to the resource specified by smbioc_ossn structure. 166681a5bbeSBoris Popov * It may either find an existing connection or try to establish a new one. 167681a5bbeSBoris Popov * If no errors occured smb_vc returned locked and referenced. 168681a5bbeSBoris Popov */ 169681a5bbeSBoris Popov int 170681a5bbeSBoris Popov smb_usr_opensession(struct smbioc_ossn *dp, struct smb_cred *scred, 171681a5bbeSBoris Popov struct smb_vc **vcpp) 172681a5bbeSBoris Popov { 173681a5bbeSBoris Popov struct smb_vc *vcp = NULL; 174681a5bbeSBoris Popov struct smb_vcspec vspec; 175681a5bbeSBoris Popov int error; 176681a5bbeSBoris Popov 177681a5bbeSBoris Popov error = smb_usr_vc2spec(dp, &vspec); 178681a5bbeSBoris Popov if (error) 179681a5bbeSBoris Popov return error; 180681a5bbeSBoris Popov if (dp->ioc_opt & SMBVOPT_CREATE) 181681a5bbeSBoris Popov vspec.flags |= SMBV_CREATE; 182681a5bbeSBoris Popov 183681a5bbeSBoris Popov error = smb_sm_lookup(&vspec, NULL, scred, &vcp); 184681a5bbeSBoris Popov smb_usr_vcspec_free(&vspec); 185681a5bbeSBoris Popov return error; 186681a5bbeSBoris Popov } 187681a5bbeSBoris Popov 188681a5bbeSBoris Popov int 189681a5bbeSBoris Popov smb_usr_openshare(struct smb_vc *vcp, struct smbioc_oshare *dp, 190681a5bbeSBoris Popov struct smb_cred *scred, struct smb_share **sspp) 191681a5bbeSBoris Popov { 192681a5bbeSBoris Popov struct smb_share *ssp; 193681a5bbeSBoris Popov struct smb_sharespec shspec; 194681a5bbeSBoris Popov int error; 195681a5bbeSBoris Popov 196681a5bbeSBoris Popov error = smb_usr_share2spec(dp, &shspec); 197681a5bbeSBoris Popov if (error) 198681a5bbeSBoris Popov return error; 199681a5bbeSBoris Popov error = smb_vc_lookupshare(vcp, &shspec, scred, &ssp); 200681a5bbeSBoris Popov if (error == 0) { 201681a5bbeSBoris Popov *sspp = ssp; 202681a5bbeSBoris Popov return 0; 203681a5bbeSBoris Popov } 204681a5bbeSBoris Popov if ((dp->ioc_opt & SMBSOPT_CREATE) == 0) 205681a5bbeSBoris Popov return error; 206681a5bbeSBoris Popov error = smb_share_create(vcp, &shspec, scred, &ssp); 207681a5bbeSBoris Popov if (error) 208681a5bbeSBoris Popov return error; 209681a5bbeSBoris Popov error = smb_smb_treeconnect(ssp, scred); 210681a5bbeSBoris Popov if (error) { 211681a5bbeSBoris Popov smb_share_put(ssp, scred); 212681a5bbeSBoris Popov } else 213681a5bbeSBoris Popov *sspp = ssp; 214681a5bbeSBoris Popov return error; 215681a5bbeSBoris Popov } 216681a5bbeSBoris Popov 217681a5bbeSBoris Popov int 218681a5bbeSBoris Popov smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp, 219681a5bbeSBoris Popov struct smb_cred *scred) 220681a5bbeSBoris Popov { 221681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 222681a5bbeSBoris Popov struct mbchain *mbp; 223681a5bbeSBoris Popov struct mdchain *mdp; 224681a5bbeSBoris Popov u_int8_t wc; 225681a5bbeSBoris Popov u_int16_t bc; 226681a5bbeSBoris Popov int error; 227681a5bbeSBoris Popov 228681a5bbeSBoris Popov switch (dp->ioc_cmd) { 229681a5bbeSBoris Popov case SMB_COM_TRANSACTION2: 230681a5bbeSBoris Popov case SMB_COM_TRANSACTION2_SECONDARY: 231681a5bbeSBoris Popov case SMB_COM_CLOSE_AND_TREE_DISC: 232681a5bbeSBoris Popov case SMB_COM_TREE_CONNECT: 233681a5bbeSBoris Popov case SMB_COM_TREE_DISCONNECT: 234681a5bbeSBoris Popov case SMB_COM_NEGOTIATE: 235681a5bbeSBoris Popov case SMB_COM_SESSION_SETUP_ANDX: 236681a5bbeSBoris Popov case SMB_COM_LOGOFF_ANDX: 237681a5bbeSBoris Popov case SMB_COM_TREE_CONNECT_ANDX: 238681a5bbeSBoris Popov return EPERM; 239681a5bbeSBoris Popov } 240681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred); 241681a5bbeSBoris Popov if (error) 242681a5bbeSBoris Popov return error; 243681a5bbeSBoris Popov mbp = &rqp->sr_rq; 244681a5bbeSBoris Popov smb_rq_wstart(rqp); 245681a5bbeSBoris Popov error = mb_put_mem(mbp, dp->ioc_twords, dp->ioc_twc * 2, MB_MUSER); 246681a5bbeSBoris Popov if (error) 247681a5bbeSBoris Popov goto bad; 248681a5bbeSBoris Popov smb_rq_wend(rqp); 249681a5bbeSBoris Popov smb_rq_bstart(rqp); 250681a5bbeSBoris Popov error = mb_put_mem(mbp, dp->ioc_tbytes, dp->ioc_tbc, MB_MUSER); 251681a5bbeSBoris Popov if (error) 252681a5bbeSBoris Popov goto bad; 253681a5bbeSBoris Popov smb_rq_bend(rqp); 254681a5bbeSBoris Popov error = smb_rq_simple(rqp); 255681a5bbeSBoris Popov if (error) 256681a5bbeSBoris Popov goto bad; 257681a5bbeSBoris Popov mdp = &rqp->sr_rp; 258681a5bbeSBoris Popov md_get_uint8(mdp, &wc); 259681a5bbeSBoris Popov dp->ioc_rwc = wc; 260681a5bbeSBoris Popov wc *= 2; 261681a5bbeSBoris Popov if (wc > dp->ioc_rpbufsz) { 262681a5bbeSBoris Popov error = EBADRPC; 263681a5bbeSBoris Popov goto bad; 264681a5bbeSBoris Popov } 265681a5bbeSBoris Popov error = md_get_mem(mdp, dp->ioc_rpbuf, wc, MB_MUSER); 266681a5bbeSBoris Popov if (error) 267681a5bbeSBoris Popov goto bad; 268681a5bbeSBoris Popov md_get_uint16le(mdp, &bc); 269681a5bbeSBoris Popov if ((wc + bc) > dp->ioc_rpbufsz) { 270681a5bbeSBoris Popov error = EBADRPC; 271681a5bbeSBoris Popov goto bad; 272681a5bbeSBoris Popov } 273681a5bbeSBoris Popov dp->ioc_rbc = bc; 274681a5bbeSBoris Popov error = md_get_mem(mdp, dp->ioc_rpbuf + wc, bc, MB_MUSER); 275681a5bbeSBoris Popov bad: 276681a5bbeSBoris Popov dp->ioc_errclass = rqp->sr_errclass; 277681a5bbeSBoris Popov dp->ioc_serror = rqp->sr_serror; 278681a5bbeSBoris Popov dp->ioc_error = rqp->sr_error; 279681a5bbeSBoris Popov smb_rq_done(rqp); 280681a5bbeSBoris Popov return error; 281681a5bbeSBoris Popov 282681a5bbeSBoris Popov } 283681a5bbeSBoris Popov 284681a5bbeSBoris Popov static int 285681a5bbeSBoris Popov smb_cpdatain(struct mbchain *mbp, int len, caddr_t data) 286681a5bbeSBoris Popov { 287681a5bbeSBoris Popov int error; 288681a5bbeSBoris Popov 289681a5bbeSBoris Popov if (len == 0) 290681a5bbeSBoris Popov return 0; 291681a5bbeSBoris Popov error = mb_init(mbp); 292681a5bbeSBoris Popov if (error) 293681a5bbeSBoris Popov return error; 294681a5bbeSBoris Popov return mb_put_mem(mbp, data, len, MB_MUSER); 295681a5bbeSBoris Popov } 296681a5bbeSBoris Popov 297681a5bbeSBoris Popov int 298681a5bbeSBoris Popov smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *dp, 299681a5bbeSBoris Popov struct smb_cred *scred) 300681a5bbeSBoris Popov { 301681a5bbeSBoris Popov struct smb_t2rq t2, *t2p = &t2; 302681a5bbeSBoris Popov struct mdchain *mdp; 303681a5bbeSBoris Popov int error, len; 304681a5bbeSBoris Popov 3057d6207b7SPeter Wemm if (dp->ioc_setupcnt > 3) 306681a5bbeSBoris Popov return EINVAL; 307681a5bbeSBoris Popov error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup[0], scred); 308681a5bbeSBoris Popov if (error) 309681a5bbeSBoris Popov return error; 310681a5bbeSBoris Popov len = t2p->t2_setupcount = dp->ioc_setupcnt; 311681a5bbeSBoris Popov if (len > 1) 312681a5bbeSBoris Popov t2p->t2_setupdata = dp->ioc_setup; 313681a5bbeSBoris Popov if (dp->ioc_name) { 314681a5bbeSBoris Popov t2p->t_name = smb_strdupin(dp->ioc_name, 128); 315681a5bbeSBoris Popov if (t2p->t_name == NULL) { 316681a5bbeSBoris Popov error = ENOMEM; 317681a5bbeSBoris Popov goto bad; 318681a5bbeSBoris Popov } 319681a5bbeSBoris Popov } 320681a5bbeSBoris Popov t2p->t2_maxscount = 0; 321681a5bbeSBoris Popov t2p->t2_maxpcount = dp->ioc_rparamcnt; 322681a5bbeSBoris Popov t2p->t2_maxdcount = dp->ioc_rdatacnt; 323681a5bbeSBoris Popov error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt, dp->ioc_tparam); 324681a5bbeSBoris Popov if (error) 325681a5bbeSBoris Popov goto bad; 326681a5bbeSBoris Popov error = smb_cpdatain(&t2p->t2_tdata, dp->ioc_tdatacnt, dp->ioc_tdata); 327681a5bbeSBoris Popov if (error) 328681a5bbeSBoris Popov goto bad; 329681a5bbeSBoris Popov error = smb_t2_request(t2p); 330681a5bbeSBoris Popov if (error) 331681a5bbeSBoris Popov goto bad; 332681a5bbeSBoris Popov mdp = &t2p->t2_rparam; 333681a5bbeSBoris Popov if (mdp->md_top) { 334681a5bbeSBoris Popov len = m_fixhdr(mdp->md_top); 335681a5bbeSBoris Popov if (len > dp->ioc_rparamcnt) { 336681a5bbeSBoris Popov error = EMSGSIZE; 337681a5bbeSBoris Popov goto bad; 338681a5bbeSBoris Popov } 339681a5bbeSBoris Popov dp->ioc_rparamcnt = len; 340681a5bbeSBoris Popov error = md_get_mem(mdp, dp->ioc_rparam, len, MB_MUSER); 341681a5bbeSBoris Popov if (error) 342681a5bbeSBoris Popov goto bad; 343681a5bbeSBoris Popov } else 344681a5bbeSBoris Popov dp->ioc_rparamcnt = 0; 345681a5bbeSBoris Popov mdp = &t2p->t2_rdata; 346681a5bbeSBoris Popov if (mdp->md_top) { 347681a5bbeSBoris Popov len = m_fixhdr(mdp->md_top); 348681a5bbeSBoris Popov if (len > dp->ioc_rdatacnt) { 349681a5bbeSBoris Popov error = EMSGSIZE; 350681a5bbeSBoris Popov goto bad; 351681a5bbeSBoris Popov } 352681a5bbeSBoris Popov dp->ioc_rdatacnt = len; 353681a5bbeSBoris Popov error = md_get_mem(mdp, dp->ioc_rdata, len, MB_MUSER); 354681a5bbeSBoris Popov } else 355681a5bbeSBoris Popov dp->ioc_rdatacnt = 0; 356681a5bbeSBoris Popov bad: 357681a5bbeSBoris Popov if (t2p->t_name) 358681a5bbeSBoris Popov smb_strfree(t2p->t_name); 359681a5bbeSBoris Popov smb_t2_done(t2p); 360681a5bbeSBoris Popov return error; 361681a5bbeSBoris Popov } 362