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 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/malloc.h> 38 #include <sys/kernel.h> 39 #include <sys/systm.h> 40 #include <sys/conf.h> 41 #include <sys/proc.h> 42 #include <sys/fcntl.h> 43 #include <sys/socket.h> 44 #include <sys/socketvar.h> 45 #include <sys/sysctl.h> 46 #include <sys/mbuf.h> 47 48 #include <sys/iconv.h> 49 50 #include <netsmb/smb.h> 51 #include <netsmb/smb_conn.h> 52 #include <netsmb/smb_rq.h> 53 #include <netsmb/smb_subr.h> 54 #include <netsmb/smb_dev.h> 55 56 /* 57 * helpers for nsmb device. Can be moved to the smb_dev.c file. 58 */ 59 static void smb_usr_vcspec_free(struct smb_vcspec *spec); 60 61 static int 62 smb_usr_vc2spec(struct smbioc_ossn *dp, struct smb_vcspec *spec) 63 { 64 int flags = 0; 65 66 bzero(spec, sizeof(*spec)); 67 68 #ifdef NETSMB_NO_ANON_USER 69 if (dp->ioc_user[0] == 0) 70 return EINVAL; 71 #endif 72 73 if (dp->ioc_server == NULL) 74 return EINVAL; 75 if (dp->ioc_localcs[0] == 0) { 76 SMBERROR("no local charset ?\n"); 77 return EINVAL; 78 } 79 80 spec->sap = smb_memdupin(dp->ioc_server, dp->ioc_svlen); 81 if (spec->sap == NULL) 82 return ENOMEM; 83 if (dp->ioc_local) { 84 spec->lap = smb_memdupin(dp->ioc_local, dp->ioc_lolen); 85 if (spec->lap == NULL) { 86 smb_usr_vcspec_free(spec); 87 return ENOMEM; 88 } 89 } 90 spec->srvname = dp->ioc_srvname; 91 spec->pass = dp->ioc_password; 92 spec->domain = dp->ioc_workgroup; 93 spec->username = dp->ioc_user; 94 spec->mode = dp->ioc_mode; 95 spec->rights = dp->ioc_rights; 96 spec->owner = dp->ioc_owner; 97 spec->group = dp->ioc_group; 98 spec->localcs = dp->ioc_localcs; 99 spec->servercs = dp->ioc_servercs; 100 if (dp->ioc_opt & SMBVOPT_PRIVATE) 101 flags |= SMBV_PRIVATE; 102 if (dp->ioc_opt & SMBVOPT_SINGLESHARE) 103 flags |= SMBV_PRIVATE | SMBV_SINGLESHARE; 104 spec->flags = flags; 105 return 0; 106 } 107 108 static void 109 smb_usr_vcspec_free(struct smb_vcspec *spec) 110 { 111 if (spec->sap) 112 smb_memfree(spec->sap); 113 if (spec->lap) 114 smb_memfree(spec->lap); 115 } 116 117 static int 118 smb_usr_share2spec(struct smbioc_oshare *dp, struct smb_sharespec *spec) 119 { 120 bzero(spec, sizeof(*spec)); 121 spec->mode = dp->ioc_mode; 122 spec->rights = dp->ioc_rights; 123 spec->owner = dp->ioc_owner; 124 spec->group = dp->ioc_group; 125 spec->name = dp->ioc_share; 126 spec->stype = dp->ioc_stype; 127 spec->pass = dp->ioc_password; 128 return 0; 129 } 130 131 int 132 smb_usr_lookup(struct smbioc_lookup *dp, struct smb_cred *scred, 133 struct smb_vc **vcpp, struct smb_share **sspp) 134 { 135 struct smb_vc *vcp = NULL; 136 struct smb_vcspec vspec; 137 struct smb_sharespec sspec, *sspecp = NULL; 138 int error; 139 140 if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE) 141 return EINVAL; 142 error = smb_usr_vc2spec(&dp->ioc_ssn, &vspec); 143 if (error) 144 return error; 145 if (dp->ioc_flags & SMBLK_CREATE) 146 vspec.flags |= SMBV_CREATE; 147 148 if (dp->ioc_level >= SMBL_SHARE) { 149 error = smb_usr_share2spec(&dp->ioc_sh, &sspec); 150 if (error) 151 goto out; 152 sspecp = &sspec; 153 } 154 error = smb_sm_lookup(&vspec, sspecp, scred, &vcp); 155 if (error == 0) { 156 *vcpp = vcp; 157 *sspp = vspec.ssp; 158 } 159 out: 160 smb_usr_vcspec_free(&vspec); 161 return error; 162 } 163 164 /* 165 * Connect to the resource specified by smbioc_ossn structure. 166 * It may either find an existing connection or try to establish a new one. 167 * If no errors occured smb_vc returned locked and referenced. 168 */ 169 int 170 smb_usr_opensession(struct smbioc_ossn *dp, struct smb_cred *scred, 171 struct smb_vc **vcpp) 172 { 173 struct smb_vc *vcp = NULL; 174 struct smb_vcspec vspec; 175 int error; 176 177 error = smb_usr_vc2spec(dp, &vspec); 178 if (error) 179 return error; 180 if (dp->ioc_opt & SMBVOPT_CREATE) 181 vspec.flags |= SMBV_CREATE; 182 183 error = smb_sm_lookup(&vspec, NULL, scred, &vcp); 184 smb_usr_vcspec_free(&vspec); 185 return error; 186 } 187 188 int 189 smb_usr_openshare(struct smb_vc *vcp, struct smbioc_oshare *dp, 190 struct smb_cred *scred, struct smb_share **sspp) 191 { 192 struct smb_share *ssp; 193 struct smb_sharespec shspec; 194 int error; 195 196 error = smb_usr_share2spec(dp, &shspec); 197 if (error) 198 return error; 199 error = smb_vc_lookupshare(vcp, &shspec, scred, &ssp); 200 if (error == 0) { 201 *sspp = ssp; 202 return 0; 203 } 204 if ((dp->ioc_opt & SMBSOPT_CREATE) == 0) 205 return error; 206 error = smb_share_create(vcp, &shspec, scred, &ssp); 207 if (error) 208 return error; 209 error = smb_smb_treeconnect(ssp, scred); 210 if (error) { 211 smb_share_put(ssp, scred); 212 } else 213 *sspp = ssp; 214 return error; 215 } 216 217 int 218 smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp, 219 struct smb_cred *scred) 220 { 221 struct smb_rq rq, *rqp = &rq; 222 struct mbchain *mbp; 223 struct mdchain *mdp; 224 u_int8_t wc; 225 u_int16_t bc; 226 int error; 227 228 switch (dp->ioc_cmd) { 229 case SMB_COM_TRANSACTION2: 230 case SMB_COM_TRANSACTION2_SECONDARY: 231 case SMB_COM_CLOSE_AND_TREE_DISC: 232 case SMB_COM_TREE_CONNECT: 233 case SMB_COM_TREE_DISCONNECT: 234 case SMB_COM_NEGOTIATE: 235 case SMB_COM_SESSION_SETUP_ANDX: 236 case SMB_COM_LOGOFF_ANDX: 237 case SMB_COM_TREE_CONNECT_ANDX: 238 return EPERM; 239 } 240 error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred); 241 if (error) 242 return error; 243 mbp = &rqp->sr_rq; 244 smb_rq_wstart(rqp); 245 error = mb_put_mem(mbp, dp->ioc_twords, dp->ioc_twc * 2, MB_MUSER); 246 if (error) 247 goto bad; 248 smb_rq_wend(rqp); 249 smb_rq_bstart(rqp); 250 error = mb_put_mem(mbp, dp->ioc_tbytes, dp->ioc_tbc, MB_MUSER); 251 if (error) 252 goto bad; 253 smb_rq_bend(rqp); 254 error = smb_rq_simple(rqp); 255 if (error) 256 goto bad; 257 mdp = &rqp->sr_rp; 258 md_get_uint8(mdp, &wc); 259 dp->ioc_rwc = wc; 260 wc *= 2; 261 if (wc > dp->ioc_rpbufsz) { 262 error = EBADRPC; 263 goto bad; 264 } 265 error = md_get_mem(mdp, dp->ioc_rpbuf, wc, MB_MUSER); 266 if (error) 267 goto bad; 268 md_get_uint16le(mdp, &bc); 269 if ((wc + bc) > dp->ioc_rpbufsz) { 270 error = EBADRPC; 271 goto bad; 272 } 273 dp->ioc_rbc = bc; 274 error = md_get_mem(mdp, dp->ioc_rpbuf + wc, bc, MB_MUSER); 275 bad: 276 dp->ioc_errclass = rqp->sr_errclass; 277 dp->ioc_serror = rqp->sr_serror; 278 dp->ioc_error = rqp->sr_error; 279 smb_rq_done(rqp); 280 return error; 281 282 } 283 284 static int 285 smb_cpdatain(struct mbchain *mbp, int len, caddr_t data) 286 { 287 int error; 288 289 if (len == 0) 290 return 0; 291 error = mb_init(mbp); 292 if (error) 293 return error; 294 return mb_put_mem(mbp, data, len, MB_MUSER); 295 } 296 297 int 298 smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *dp, 299 struct smb_cred *scred) 300 { 301 struct smb_t2rq t2, *t2p = &t2; 302 struct mdchain *mdp; 303 int error, len; 304 305 if (dp->ioc_setupcnt > 3) 306 return EINVAL; 307 error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup[0], scred); 308 if (error) 309 return error; 310 len = t2p->t2_setupcount = dp->ioc_setupcnt; 311 if (len > 1) 312 t2p->t2_setupdata = dp->ioc_setup; 313 if (dp->ioc_name) { 314 t2p->t_name = smb_strdupin(dp->ioc_name, 128); 315 if (t2p->t_name == NULL) { 316 error = ENOMEM; 317 goto bad; 318 } 319 } 320 t2p->t2_maxscount = 0; 321 t2p->t2_maxpcount = dp->ioc_rparamcnt; 322 t2p->t2_maxdcount = dp->ioc_rdatacnt; 323 error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt, dp->ioc_tparam); 324 if (error) 325 goto bad; 326 error = smb_cpdatain(&t2p->t2_tdata, dp->ioc_tdatacnt, dp->ioc_tdata); 327 if (error) 328 goto bad; 329 error = smb_t2_request(t2p); 330 if (error) 331 goto bad; 332 mdp = &t2p->t2_rparam; 333 if (mdp->md_top) { 334 len = m_fixhdr(mdp->md_top); 335 if (len > dp->ioc_rparamcnt) { 336 error = EMSGSIZE; 337 goto bad; 338 } 339 dp->ioc_rparamcnt = len; 340 error = md_get_mem(mdp, dp->ioc_rparam, len, MB_MUSER); 341 if (error) 342 goto bad; 343 } else 344 dp->ioc_rparamcnt = 0; 345 mdp = &t2p->t2_rdata; 346 if (mdp->md_top) { 347 len = m_fixhdr(mdp->md_top); 348 if (len > dp->ioc_rdatacnt) { 349 error = EMSGSIZE; 350 goto bad; 351 } 352 dp->ioc_rdatacnt = len; 353 error = md_get_mem(mdp, dp->ioc_rdata, len, MB_MUSER); 354 } else 355 dp->ioc_rdatacnt = 0; 356 bad: 357 if (t2p->t_name) 358 smb_strfree(t2p->t_name); 359 smb_t2_done(t2p); 360 return error; 361 } 362