1/* $NetBSD: smb_usr.c,v 1.15 2008/06/24 10:37:19 gmcgarry Exp $ */ 2 3/* 4 * Copyright (c) 2000-2001 Boris Popov 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Boris Popov. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * FreeBSD: src/sys/netsmb/smb_usr.c,v 1.1 2001/04/10 07:59:06 bp Exp 35 */ 36 37#include <sys/cdefs.h> 38__KERNEL_RCSID(0, "$NetBSD: smb_usr.c,v 1.15 2008/06/24 10:37:19 gmcgarry Exp $"); 39 40#include <sys/param.h> 41#include <sys/malloc.h> 42#include <sys/kernel.h> 43#include <sys/systm.h> 44#include <sys/conf.h> 45#include <sys/proc.h> 46#include <sys/fcntl.h> 47#include <sys/socket.h> 48#include <sys/socketvar.h> 49#include <sys/sysctl.h> 50 51#include <netsmb/iconv.h> 52 53#include <netsmb/smb.h> 54#include <netsmb/smb_conn.h> 55#include <netsmb/smb_rq.h> 56#include <netsmb/smb_subr.h> 57#include <netsmb/smb_dev.h> 58 59/* 60 * helpers for nsmb device. Can be moved to the smb_dev.c file. 61 */ 62static void smb_usr_vcspec_free(struct smb_vcspec *spec); 63 64static int 65smb_usr_vc2spec(struct smbioc_ossn *dp, struct smb_vcspec *spec) 66{ 67 int flags = 0; 68 69 memset(spec, 0, sizeof(*spec)); 70 if (dp->ioc_user[0] == 0) 71 return EINVAL; 72 if (dp->ioc_server == NULL) 73 return EINVAL; 74 if (dp->ioc_localcs[0] == 0) { 75 SMBERROR(("no local charset ?\n")); 76 return EINVAL; 77 } 78 79 spec->sap = smb_memdupin(dp->ioc_server, dp->ioc_svlen); 80 if (spec->sap == NULL) 81 return ENOMEM; 82 if (dp->ioc_local) { 83 spec->lap = smb_memdupin(dp->ioc_local, dp->ioc_lolen); 84 if (spec->lap == NULL) { 85 smb_usr_vcspec_free(spec); 86 return ENOMEM; 87 } 88 } 89 spec->srvname = dp->ioc_srvname; 90 spec->pass = dp->ioc_password; 91 spec->domain = dp->ioc_workgroup; 92 spec->username = dp->ioc_user; 93 spec->mode = dp->ioc_mode; 94 spec->rights = dp->ioc_rights; 95 spec->owner = dp->ioc_owner; 96 spec->group = dp->ioc_group; 97 spec->localcs = dp->ioc_localcs; 98 spec->servercs = dp->ioc_servercs; 99 if (dp->ioc_opt & SMBVOPT_PRIVATE) 100 flags |= SMBV_PRIVATE; 101 if (dp->ioc_opt & SMBVOPT_SINGLESHARE) 102 flags |= SMBV_PRIVATE | SMBV_SINGLESHARE; 103 spec->flags = flags; 104 return 0; 105} 106 107static void 108smb_usr_vcspec_free(struct smb_vcspec *spec) 109{ 110 if (spec->sap) 111 smb_memfree(spec->sap); 112 if (spec->lap) 113 smb_memfree(spec->lap); 114} 115 116static int 117smb_usr_share2spec(struct smbioc_oshare *dp, struct smb_sharespec *spec) 118{ 119 memset(spec, 0, sizeof(*spec)); 120 spec->mode = dp->ioc_mode; 121 spec->rights = dp->ioc_rights; 122 spec->owner = dp->ioc_owner; 123 spec->group = dp->ioc_group; 124 spec->name = dp->ioc_share; 125 spec->stype = dp->ioc_stype; 126 spec->pass = dp->ioc_password; 127 return 0; 128} 129 130int 131smb_usr_lookup(struct smbioc_lookup *dp, struct smb_cred *scred, 132 struct smb_vc **vcpp, struct smb_share **sspp) 133{ 134 struct smb_vc *vcp = NULL; 135 struct smb_vcspec vspec; 136 struct smb_sharespec sspec, *sspecp = NULL; 137 int error; 138 139 if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE) 140 return EINVAL; 141 error = smb_usr_vc2spec(&dp->ioc_ssn, &vspec); 142 if (error) 143 return error; 144 if (dp->ioc_flags & SMBLK_CREATE) 145 vspec.flags |= SMBV_CREATE; 146 147 if (dp->ioc_level >= SMBL_SHARE) { 148 error = smb_usr_share2spec(&dp->ioc_sh, &sspec); 149 if (error) 150 goto out; 151 sspecp = &sspec; 152 } 153 error = smb_sm_lookup(&vspec, sspecp, scred, &vcp); 154 if (error == 0) { 155 *vcpp = vcp; 156 *sspp = vspec.ssp; 157 } 158out: 159 smb_usr_vcspec_free(&vspec); 160 return error; 161} 162 163/* 164 * Connect to the resource specified by smbioc_ossn structure. 165 * It may either find an existing connection or try to establish a new one. 166 * If no errors occurred smb_vc returned locked and referenced. 167 */ 168int 169smb_usr_opensession(struct smbioc_ossn *dp, struct smb_cred *scred, 170 struct smb_vc **vcpp) 171{ 172 struct smb_vc *vcp = NULL; 173 struct smb_vcspec vspec; 174 int error; 175 176 error = smb_usr_vc2spec(dp, &vspec); 177 if (error) 178 return error; 179 if (dp->ioc_opt & SMBVOPT_CREATE) 180 vspec.flags |= SMBV_CREATE; 181 182 error = smb_sm_lookup(&vspec, NULL, scred, &vcp); 183 smb_usr_vcspec_free(&vspec); 184 return error; 185} 186 187int 188smb_usr_openshare(struct smb_vc *vcp, struct smbioc_oshare *dp, 189 struct smb_cred *scred, struct smb_share **sspp) 190{ 191 struct smb_share *ssp; 192 struct smb_sharespec shspec; 193 int error; 194 195 error = smb_usr_share2spec(dp, &shspec); 196 if (error) 197 return error; 198 error = smb_vc_lookupshare(vcp, &shspec, scred, &ssp); 199 if (error == 0) { 200 *sspp = ssp; 201 return 0; 202 } 203 if ((dp->ioc_opt & SMBSOPT_CREATE) == 0) 204 return error; 205 error = smb_share_create(vcp, &shspec, scred, &ssp); 206 if (error) 207 return error; 208 error = smb_smb_treeconnect(ssp, scred); 209 if (error) { 210 smb_share_put(ssp, scred); 211 } else 212 *sspp = ssp; 213 return error; 214} 215 216int 217smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp, 218 struct smb_cred *scred) 219{ 220 struct smb_rq *rqp; 221 struct mbchain *mbp; 222 struct mdchain *mdp; 223 u_int8_t wc; 224 u_int16_t bc; 225 int error; 226 227 switch (dp->ioc_cmd) { 228 case SMB_COM_TRANSACTION2: 229 case SMB_COM_TRANSACTION2_SECONDARY: 230 case SMB_COM_CLOSE_AND_TREE_DISC: 231 case SMB_COM_TREE_CONNECT: 232 case SMB_COM_TREE_DISCONNECT: 233 case SMB_COM_NEGOTIATE: 234 case SMB_COM_SESSION_SETUP_ANDX: 235 case SMB_COM_LOGOFF_ANDX: 236 case SMB_COM_TREE_CONNECT_ANDX: 237 return EPERM; 238 } 239 error = smb_rq_alloc(SSTOCP(ssp), dp->ioc_cmd, scred, &rqp); 240 if (error) 241 return error; 242 mbp = &rqp->sr_rq; 243 smb_rq_wstart(rqp); 244 error = mb_put_mem(mbp, dp->ioc_twords, dp->ioc_twc * 2, MB_MUSER); 245 if (error) 246 goto bad; 247 smb_rq_wend(rqp); 248 smb_rq_bstart(rqp); 249 error = mb_put_mem(mbp, dp->ioc_tbytes, dp->ioc_tbc, MB_MUSER); 250 if (error) 251 goto bad; 252 smb_rq_bend(rqp); 253 error = smb_rq_simple(rqp); 254 if (error) 255 goto bad; 256 mdp = &rqp->sr_rp; 257 md_get_uint8(mdp, &wc); 258 dp->ioc_rwc = wc; 259 wc *= 2; 260 if (wc > dp->ioc_rpbufsz) { 261 error = EBADRPC; 262 goto bad; 263 } 264 error = md_get_mem(mdp, dp->ioc_rpbuf, wc, MB_MUSER); 265 if (error) 266 goto bad; 267 md_get_uint16le(mdp, &bc); 268 if ((wc + bc) > dp->ioc_rpbufsz) { 269 error = EBADRPC; 270 goto bad; 271 } 272 dp->ioc_rbc = bc; 273 error = md_get_mem(mdp, dp->ioc_rpbuf + wc, bc, MB_MUSER); 274bad: 275 smb_rq_done(rqp); 276 return error; 277 278} 279 280static int 281smb_cpdatain(struct mbchain *mbp, int len, void *data) 282{ 283 int error; 284 285 if (len == 0) 286 return 0; 287 error = mb_init(mbp); 288 if (error) 289 return error; 290 return mb_put_mem(mbp, data, len, MB_MUSER); 291} 292 293int 294smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *dp, 295 struct smb_cred *scred) 296{ 297 struct smb_t2rq *t2p; 298 struct mdchain *mdp; 299 int error, len; 300 301 if (dp->ioc_setupcnt > 3) 302 return EINVAL; 303 error = smb_t2_alloc(SSTOCP(ssp), dp->ioc_setup[0], scred, &t2p); 304 if (error) 305 return error; 306 len = t2p->t2_setupcount = dp->ioc_setupcnt; 307 if (len > 1) 308 t2p->t2_setupdata = dp->ioc_setup; 309 if (dp->ioc_name) { 310 t2p->t_name = smb_strdupin(dp->ioc_name, 128); 311 if (t2p->t_name == NULL) { 312 error = ENOMEM; 313 goto bad; 314 } 315 } 316 t2p->t2_maxscount = 0; 317 t2p->t2_maxpcount = dp->ioc_rparamcnt; 318 t2p->t2_maxdcount = dp->ioc_rdatacnt; 319 error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt, dp->ioc_tparam); 320 if (error) 321 goto bad; 322 error = smb_cpdatain(&t2p->t2_tdata, dp->ioc_tdatacnt, dp->ioc_tdata); 323 if (error) 324 goto bad; 325 error = smb_t2_request(t2p); 326 if (error) 327 goto bad; 328 mdp = &t2p->t2_rparam; 329 if (mdp->md_top) { 330 len = m_fixhdr(mdp->md_top); 331 if (len > dp->ioc_rparamcnt) { 332 error = EMSGSIZE; 333 goto bad; 334 } 335 dp->ioc_rparamcnt = len; 336 error = md_get_mem(mdp, dp->ioc_rparam, len, MB_MUSER); 337 if (error) 338 goto bad; 339 } else 340 dp->ioc_rparamcnt = 0; 341 mdp = &t2p->t2_rdata; 342 if (mdp->md_top) { 343 len = m_fixhdr(mdp->md_top); 344 if (len > dp->ioc_rdatacnt) { 345 error = EMSGSIZE; 346 goto bad; 347 } 348 dp->ioc_rdatacnt = len; 349 error = md_get_mem(mdp, dp->ioc_rdata, len, MB_MUSER); 350 } else 351 dp->ioc_rdatacnt = 0; 352bad: 353 if (t2p->t_name) 354 smb_strfree(t2p->t_name); 355 smb_t2_done(t2p); 356 return error; 357} 358