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