1681a5bbeSBoris Popov /* 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 * 32681a5bbeSBoris Popov * $FreeBSD$ 33681a5bbeSBoris Popov */ 34681a5bbeSBoris Popov #include <sys/param.h> 35681a5bbeSBoris Popov #include <sys/malloc.h> 36681a5bbeSBoris Popov #include <sys/kernel.h> 37681a5bbeSBoris Popov #include <sys/systm.h> 38681a5bbeSBoris Popov #include <sys/conf.h> 39681a5bbeSBoris Popov #include <sys/proc.h> 40681a5bbeSBoris Popov #include <sys/fcntl.h> 41681a5bbeSBoris Popov #include <sys/socket.h> 42681a5bbeSBoris Popov #include <sys/socketvar.h> 43681a5bbeSBoris Popov #include <sys/sysctl.h> 449f86067aSPoul-Henning Kamp #include <sys/mbuf.h> 45681a5bbeSBoris Popov 46681a5bbeSBoris Popov #include <sys/iconv.h> 47681a5bbeSBoris Popov 48681a5bbeSBoris Popov #include <netsmb/smb.h> 49681a5bbeSBoris Popov #include <netsmb/smb_conn.h> 50681a5bbeSBoris Popov #include <netsmb/smb_rq.h> 51681a5bbeSBoris Popov #include <netsmb/smb_subr.h> 52681a5bbeSBoris Popov #include <netsmb/smb_dev.h> 53681a5bbeSBoris Popov 54681a5bbeSBoris Popov /* 55681a5bbeSBoris Popov * helpers for nsmb device. Can be moved to the smb_dev.c file. 56681a5bbeSBoris Popov */ 57681a5bbeSBoris Popov static void smb_usr_vcspec_free(struct smb_vcspec *spec); 58681a5bbeSBoris Popov 59681a5bbeSBoris Popov static int 60681a5bbeSBoris Popov smb_usr_vc2spec(struct smbioc_ossn *dp, struct smb_vcspec *spec) 61681a5bbeSBoris Popov { 62681a5bbeSBoris Popov int flags = 0; 63681a5bbeSBoris Popov 64681a5bbeSBoris Popov bzero(spec, sizeof(*spec)); 65994ad180SBoris Popov 66994ad180SBoris Popov #ifdef NETSMB_NO_ANON_USER 67681a5bbeSBoris Popov if (dp->ioc_user[0] == 0) 68681a5bbeSBoris Popov return EINVAL; 69994ad180SBoris Popov #endif 70994ad180SBoris Popov 71681a5bbeSBoris Popov if (dp->ioc_server == NULL) 72681a5bbeSBoris Popov return EINVAL; 73681a5bbeSBoris Popov if (dp->ioc_localcs[0] == 0) { 74681a5bbeSBoris Popov SMBERROR("no local charset ?\n"); 75681a5bbeSBoris Popov return EINVAL; 76681a5bbeSBoris Popov } 77681a5bbeSBoris Popov 78681a5bbeSBoris Popov spec->sap = smb_memdupin(dp->ioc_server, dp->ioc_svlen); 79681a5bbeSBoris Popov if (spec->sap == NULL) 80681a5bbeSBoris Popov return ENOMEM; 81681a5bbeSBoris Popov if (dp->ioc_local) { 82681a5bbeSBoris Popov spec->lap = smb_memdupin(dp->ioc_local, dp->ioc_lolen); 83681a5bbeSBoris Popov if (spec->lap == NULL) { 84681a5bbeSBoris Popov smb_usr_vcspec_free(spec); 85681a5bbeSBoris Popov return ENOMEM; 86681a5bbeSBoris Popov } 87681a5bbeSBoris Popov } 88681a5bbeSBoris Popov spec->srvname = dp->ioc_srvname; 89681a5bbeSBoris Popov spec->pass = dp->ioc_password; 90681a5bbeSBoris Popov spec->domain = dp->ioc_workgroup; 91681a5bbeSBoris Popov spec->username = dp->ioc_user; 92681a5bbeSBoris Popov spec->mode = dp->ioc_mode; 93681a5bbeSBoris Popov spec->rights = dp->ioc_rights; 94681a5bbeSBoris Popov spec->owner = dp->ioc_owner; 95681a5bbeSBoris Popov spec->group = dp->ioc_group; 96681a5bbeSBoris Popov spec->localcs = dp->ioc_localcs; 97681a5bbeSBoris Popov spec->servercs = dp->ioc_servercs; 98681a5bbeSBoris Popov if (dp->ioc_opt & SMBVOPT_PRIVATE) 99681a5bbeSBoris Popov flags |= SMBV_PRIVATE; 100681a5bbeSBoris Popov if (dp->ioc_opt & SMBVOPT_SINGLESHARE) 101681a5bbeSBoris Popov flags |= SMBV_PRIVATE | SMBV_SINGLESHARE; 102681a5bbeSBoris Popov spec->flags = flags; 103681a5bbeSBoris Popov return 0; 104681a5bbeSBoris Popov } 105681a5bbeSBoris Popov 106681a5bbeSBoris Popov static void 107681a5bbeSBoris Popov smb_usr_vcspec_free(struct smb_vcspec *spec) 108681a5bbeSBoris Popov { 109681a5bbeSBoris Popov if (spec->sap) 110681a5bbeSBoris Popov smb_memfree(spec->sap); 111681a5bbeSBoris Popov if (spec->lap) 112681a5bbeSBoris Popov smb_memfree(spec->lap); 113681a5bbeSBoris Popov } 114681a5bbeSBoris Popov 115681a5bbeSBoris Popov static int 116681a5bbeSBoris Popov smb_usr_share2spec(struct smbioc_oshare *dp, struct smb_sharespec *spec) 117681a5bbeSBoris Popov { 118681a5bbeSBoris Popov bzero(spec, sizeof(*spec)); 119681a5bbeSBoris Popov spec->mode = dp->ioc_mode; 120681a5bbeSBoris Popov spec->rights = dp->ioc_rights; 121681a5bbeSBoris Popov spec->owner = dp->ioc_owner; 122681a5bbeSBoris Popov spec->group = dp->ioc_group; 123681a5bbeSBoris Popov spec->name = dp->ioc_share; 124681a5bbeSBoris Popov spec->stype = dp->ioc_stype; 125681a5bbeSBoris Popov spec->pass = dp->ioc_password; 126681a5bbeSBoris Popov return 0; 127681a5bbeSBoris Popov } 128681a5bbeSBoris Popov 129681a5bbeSBoris Popov int 130681a5bbeSBoris Popov smb_usr_lookup(struct smbioc_lookup *dp, struct smb_cred *scred, 131681a5bbeSBoris Popov struct smb_vc **vcpp, struct smb_share **sspp) 132681a5bbeSBoris Popov { 133681a5bbeSBoris Popov struct smb_vc *vcp = NULL; 134681a5bbeSBoris Popov struct smb_vcspec vspec; 135681a5bbeSBoris Popov struct smb_sharespec sspec, *sspecp = NULL; 136681a5bbeSBoris Popov int error; 137681a5bbeSBoris Popov 138681a5bbeSBoris Popov if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE) 139681a5bbeSBoris Popov return EINVAL; 140681a5bbeSBoris Popov error = smb_usr_vc2spec(&dp->ioc_ssn, &vspec); 141681a5bbeSBoris Popov if (error) 142681a5bbeSBoris Popov return error; 143681a5bbeSBoris Popov if (dp->ioc_flags & SMBLK_CREATE) 144681a5bbeSBoris Popov vspec.flags |= SMBV_CREATE; 145681a5bbeSBoris Popov 146681a5bbeSBoris Popov if (dp->ioc_level >= SMBL_SHARE) { 147681a5bbeSBoris Popov error = smb_usr_share2spec(&dp->ioc_sh, &sspec); 148681a5bbeSBoris Popov if (error) 149681a5bbeSBoris Popov goto out; 150681a5bbeSBoris Popov sspecp = &sspec; 151681a5bbeSBoris Popov } 152681a5bbeSBoris Popov error = smb_sm_lookup(&vspec, sspecp, scred, &vcp); 153681a5bbeSBoris Popov if (error == 0) { 154681a5bbeSBoris Popov *vcpp = vcp; 155681a5bbeSBoris Popov *sspp = vspec.ssp; 156681a5bbeSBoris Popov } 157681a5bbeSBoris Popov out: 158681a5bbeSBoris Popov smb_usr_vcspec_free(&vspec); 159681a5bbeSBoris Popov return error; 160681a5bbeSBoris Popov } 161681a5bbeSBoris Popov 162681a5bbeSBoris Popov /* 163681a5bbeSBoris Popov * Connect to the resource specified by smbioc_ossn structure. 164681a5bbeSBoris Popov * It may either find an existing connection or try to establish a new one. 165681a5bbeSBoris Popov * If no errors occured smb_vc returned locked and referenced. 166681a5bbeSBoris Popov */ 167681a5bbeSBoris Popov int 168681a5bbeSBoris Popov smb_usr_opensession(struct smbioc_ossn *dp, struct smb_cred *scred, 169681a5bbeSBoris Popov struct smb_vc **vcpp) 170681a5bbeSBoris Popov { 171681a5bbeSBoris Popov struct smb_vc *vcp = NULL; 172681a5bbeSBoris Popov struct smb_vcspec vspec; 173681a5bbeSBoris Popov int error; 174681a5bbeSBoris Popov 175681a5bbeSBoris Popov error = smb_usr_vc2spec(dp, &vspec); 176681a5bbeSBoris Popov if (error) 177681a5bbeSBoris Popov return error; 178681a5bbeSBoris Popov if (dp->ioc_opt & SMBVOPT_CREATE) 179681a5bbeSBoris Popov vspec.flags |= SMBV_CREATE; 180681a5bbeSBoris Popov 181681a5bbeSBoris Popov error = smb_sm_lookup(&vspec, NULL, scred, &vcp); 182681a5bbeSBoris Popov smb_usr_vcspec_free(&vspec); 183681a5bbeSBoris Popov return error; 184681a5bbeSBoris Popov } 185681a5bbeSBoris Popov 186681a5bbeSBoris Popov int 187681a5bbeSBoris Popov smb_usr_openshare(struct smb_vc *vcp, struct smbioc_oshare *dp, 188681a5bbeSBoris Popov struct smb_cred *scred, struct smb_share **sspp) 189681a5bbeSBoris Popov { 190681a5bbeSBoris Popov struct smb_share *ssp; 191681a5bbeSBoris Popov struct smb_sharespec shspec; 192681a5bbeSBoris Popov int error; 193681a5bbeSBoris Popov 194681a5bbeSBoris Popov error = smb_usr_share2spec(dp, &shspec); 195681a5bbeSBoris Popov if (error) 196681a5bbeSBoris Popov return error; 197681a5bbeSBoris Popov error = smb_vc_lookupshare(vcp, &shspec, scred, &ssp); 198681a5bbeSBoris Popov if (error == 0) { 199681a5bbeSBoris Popov *sspp = ssp; 200681a5bbeSBoris Popov return 0; 201681a5bbeSBoris Popov } 202681a5bbeSBoris Popov if ((dp->ioc_opt & SMBSOPT_CREATE) == 0) 203681a5bbeSBoris Popov return error; 204681a5bbeSBoris Popov error = smb_share_create(vcp, &shspec, scred, &ssp); 205681a5bbeSBoris Popov if (error) 206681a5bbeSBoris Popov return error; 207681a5bbeSBoris Popov error = smb_smb_treeconnect(ssp, scred); 208681a5bbeSBoris Popov if (error) { 209681a5bbeSBoris Popov smb_share_put(ssp, scred); 210681a5bbeSBoris Popov } else 211681a5bbeSBoris Popov *sspp = ssp; 212681a5bbeSBoris Popov return error; 213681a5bbeSBoris Popov } 214681a5bbeSBoris Popov 215681a5bbeSBoris Popov int 216681a5bbeSBoris Popov smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp, 217681a5bbeSBoris Popov struct smb_cred *scred) 218681a5bbeSBoris Popov { 219681a5bbeSBoris Popov struct smb_rq rq, *rqp = &rq; 220681a5bbeSBoris Popov struct mbchain *mbp; 221681a5bbeSBoris Popov struct mdchain *mdp; 222681a5bbeSBoris Popov u_int8_t wc; 223681a5bbeSBoris Popov u_int16_t bc; 224681a5bbeSBoris Popov int error; 225681a5bbeSBoris Popov 226681a5bbeSBoris Popov switch (dp->ioc_cmd) { 227681a5bbeSBoris Popov case SMB_COM_TRANSACTION2: 228681a5bbeSBoris Popov case SMB_COM_TRANSACTION2_SECONDARY: 229681a5bbeSBoris Popov case SMB_COM_CLOSE_AND_TREE_DISC: 230681a5bbeSBoris Popov case SMB_COM_TREE_CONNECT: 231681a5bbeSBoris Popov case SMB_COM_TREE_DISCONNECT: 232681a5bbeSBoris Popov case SMB_COM_NEGOTIATE: 233681a5bbeSBoris Popov case SMB_COM_SESSION_SETUP_ANDX: 234681a5bbeSBoris Popov case SMB_COM_LOGOFF_ANDX: 235681a5bbeSBoris Popov case SMB_COM_TREE_CONNECT_ANDX: 236681a5bbeSBoris Popov return EPERM; 237681a5bbeSBoris Popov } 238681a5bbeSBoris Popov error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred); 239681a5bbeSBoris Popov if (error) 240681a5bbeSBoris Popov return error; 241681a5bbeSBoris Popov mbp = &rqp->sr_rq; 242681a5bbeSBoris Popov smb_rq_wstart(rqp); 243681a5bbeSBoris Popov error = mb_put_mem(mbp, dp->ioc_twords, dp->ioc_twc * 2, MB_MUSER); 244681a5bbeSBoris Popov if (error) 245681a5bbeSBoris Popov goto bad; 246681a5bbeSBoris Popov smb_rq_wend(rqp); 247681a5bbeSBoris Popov smb_rq_bstart(rqp); 248681a5bbeSBoris Popov error = mb_put_mem(mbp, dp->ioc_tbytes, dp->ioc_tbc, MB_MUSER); 249681a5bbeSBoris Popov if (error) 250681a5bbeSBoris Popov goto bad; 251681a5bbeSBoris Popov smb_rq_bend(rqp); 252681a5bbeSBoris Popov error = smb_rq_simple(rqp); 253681a5bbeSBoris Popov if (error) 254681a5bbeSBoris Popov goto bad; 255681a5bbeSBoris Popov mdp = &rqp->sr_rp; 256681a5bbeSBoris Popov md_get_uint8(mdp, &wc); 257681a5bbeSBoris Popov dp->ioc_rwc = wc; 258681a5bbeSBoris Popov wc *= 2; 259681a5bbeSBoris Popov if (wc > dp->ioc_rpbufsz) { 260681a5bbeSBoris Popov error = EBADRPC; 261681a5bbeSBoris Popov goto bad; 262681a5bbeSBoris Popov } 263681a5bbeSBoris Popov error = md_get_mem(mdp, dp->ioc_rpbuf, wc, MB_MUSER); 264681a5bbeSBoris Popov if (error) 265681a5bbeSBoris Popov goto bad; 266681a5bbeSBoris Popov md_get_uint16le(mdp, &bc); 267681a5bbeSBoris Popov if ((wc + bc) > dp->ioc_rpbufsz) { 268681a5bbeSBoris Popov error = EBADRPC; 269681a5bbeSBoris Popov goto bad; 270681a5bbeSBoris Popov } 271681a5bbeSBoris Popov dp->ioc_rbc = bc; 272681a5bbeSBoris Popov error = md_get_mem(mdp, dp->ioc_rpbuf + wc, bc, MB_MUSER); 273681a5bbeSBoris Popov bad: 274681a5bbeSBoris Popov dp->ioc_errclass = rqp->sr_errclass; 275681a5bbeSBoris Popov dp->ioc_serror = rqp->sr_serror; 276681a5bbeSBoris Popov dp->ioc_error = rqp->sr_error; 277681a5bbeSBoris Popov smb_rq_done(rqp); 278681a5bbeSBoris Popov return error; 279681a5bbeSBoris Popov 280681a5bbeSBoris Popov } 281681a5bbeSBoris Popov 282681a5bbeSBoris Popov static int 283681a5bbeSBoris Popov smb_cpdatain(struct mbchain *mbp, int len, caddr_t data) 284681a5bbeSBoris Popov { 285681a5bbeSBoris Popov int error; 286681a5bbeSBoris Popov 287681a5bbeSBoris Popov if (len == 0) 288681a5bbeSBoris Popov return 0; 289681a5bbeSBoris Popov error = mb_init(mbp); 290681a5bbeSBoris Popov if (error) 291681a5bbeSBoris Popov return error; 292681a5bbeSBoris Popov return mb_put_mem(mbp, data, len, MB_MUSER); 293681a5bbeSBoris Popov } 294681a5bbeSBoris Popov 295681a5bbeSBoris Popov int 296681a5bbeSBoris Popov smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *dp, 297681a5bbeSBoris Popov struct smb_cred *scred) 298681a5bbeSBoris Popov { 299681a5bbeSBoris Popov struct smb_t2rq t2, *t2p = &t2; 300681a5bbeSBoris Popov struct mdchain *mdp; 301681a5bbeSBoris Popov int error, len; 302681a5bbeSBoris Popov 303681a5bbeSBoris Popov if (dp->ioc_tparamcnt > 0xffff || dp->ioc_tdatacnt > 0xffff || 304681a5bbeSBoris Popov dp->ioc_setupcnt > 3) 305681a5bbeSBoris Popov return EINVAL; 306681a5bbeSBoris Popov error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup[0], scred); 307681a5bbeSBoris Popov if (error) 308681a5bbeSBoris Popov return error; 309681a5bbeSBoris Popov len = t2p->t2_setupcount = dp->ioc_setupcnt; 310681a5bbeSBoris Popov if (len > 1) 311681a5bbeSBoris Popov t2p->t2_setupdata = dp->ioc_setup; 312681a5bbeSBoris Popov if (dp->ioc_name) { 313681a5bbeSBoris Popov t2p->t_name = smb_strdupin(dp->ioc_name, 128); 314681a5bbeSBoris Popov if (t2p->t_name == NULL) { 315681a5bbeSBoris Popov error = ENOMEM; 316681a5bbeSBoris Popov goto bad; 317681a5bbeSBoris Popov } 318681a5bbeSBoris Popov } 319681a5bbeSBoris Popov t2p->t2_maxscount = 0; 320681a5bbeSBoris Popov t2p->t2_maxpcount = dp->ioc_rparamcnt; 321681a5bbeSBoris Popov t2p->t2_maxdcount = dp->ioc_rdatacnt; 322681a5bbeSBoris Popov error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt, dp->ioc_tparam); 323681a5bbeSBoris Popov if (error) 324681a5bbeSBoris Popov goto bad; 325681a5bbeSBoris Popov error = smb_cpdatain(&t2p->t2_tdata, dp->ioc_tdatacnt, dp->ioc_tdata); 326681a5bbeSBoris Popov if (error) 327681a5bbeSBoris Popov goto bad; 328681a5bbeSBoris Popov error = smb_t2_request(t2p); 329681a5bbeSBoris Popov if (error) 330681a5bbeSBoris Popov goto bad; 331681a5bbeSBoris Popov mdp = &t2p->t2_rparam; 332681a5bbeSBoris Popov if (mdp->md_top) { 333681a5bbeSBoris Popov len = m_fixhdr(mdp->md_top); 334681a5bbeSBoris Popov if (len > dp->ioc_rparamcnt) { 335681a5bbeSBoris Popov error = EMSGSIZE; 336681a5bbeSBoris Popov goto bad; 337681a5bbeSBoris Popov } 338681a5bbeSBoris Popov dp->ioc_rparamcnt = len; 339681a5bbeSBoris Popov error = md_get_mem(mdp, dp->ioc_rparam, len, MB_MUSER); 340681a5bbeSBoris Popov if (error) 341681a5bbeSBoris Popov goto bad; 342681a5bbeSBoris Popov } else 343681a5bbeSBoris Popov dp->ioc_rparamcnt = 0; 344681a5bbeSBoris Popov mdp = &t2p->t2_rdata; 345681a5bbeSBoris Popov if (mdp->md_top) { 346681a5bbeSBoris Popov len = m_fixhdr(mdp->md_top); 347681a5bbeSBoris Popov if (len > dp->ioc_rdatacnt) { 348681a5bbeSBoris Popov error = EMSGSIZE; 349681a5bbeSBoris Popov goto bad; 350681a5bbeSBoris Popov } 351681a5bbeSBoris Popov dp->ioc_rdatacnt = len; 352681a5bbeSBoris Popov error = md_get_mem(mdp, dp->ioc_rdata, len, MB_MUSER); 353681a5bbeSBoris Popov } else 354681a5bbeSBoris Popov dp->ioc_rdatacnt = 0; 355681a5bbeSBoris Popov bad: 356681a5bbeSBoris Popov if (t2p->t_name) 357681a5bbeSBoris Popov smb_strfree(t2p->t_name); 358681a5bbeSBoris Popov smb_t2_done(t2p); 359681a5bbeSBoris Popov return error; 360681a5bbeSBoris Popov } 361