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 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/malloc.h> 32 #include <sys/kernel.h> 33 #include <sys/systm.h> 34 #include <sys/conf.h> 35 #include <sys/proc.h> 36 #include <sys/fcntl.h> 37 #include <sys/socket.h> 38 #include <sys/socketvar.h> 39 #include <sys/sysctl.h> 40 #include <sys/mbuf.h> 41 42 #include <sys/iconv.h> 43 44 #include <netsmb/smb.h> 45 #include <netsmb/smb_conn.h> 46 #include <netsmb/smb_rq.h> 47 #include <netsmb/smb_subr.h> 48 #include <netsmb/smb_dev.h> 49 50 /* 51 * helpers for nsmb device. Can be moved to the smb_dev.c file. 52 */ 53 static void smb_usr_vcspec_free(struct smb_vcspec *spec); 54 55 static int 56 smb_usr_vc2spec(struct smbioc_ossn *dp, struct smb_vcspec *spec) 57 { 58 int flags = 0; 59 60 bzero(spec, sizeof(*spec)); 61 62 #ifdef NETSMB_NO_ANON_USER 63 if (dp->ioc_user[0] == 0) 64 return EINVAL; 65 #endif 66 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_setupcnt > 3) 300 return EINVAL; 301 error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup[0], scred); 302 if (error) 303 return error; 304 len = t2p->t2_setupcount = dp->ioc_setupcnt; 305 if (len > 1) 306 t2p->t2_setupdata = dp->ioc_setup; 307 if (dp->ioc_name) { 308 t2p->t_name = smb_strdupin(dp->ioc_name, 128); 309 if (t2p->t_name == NULL) { 310 error = ENOMEM; 311 goto bad; 312 } 313 } 314 t2p->t2_maxscount = 0; 315 t2p->t2_maxpcount = dp->ioc_rparamcnt; 316 t2p->t2_maxdcount = dp->ioc_rdatacnt; 317 error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt, dp->ioc_tparam); 318 if (error) 319 goto bad; 320 error = smb_cpdatain(&t2p->t2_tdata, dp->ioc_tdatacnt, dp->ioc_tdata); 321 if (error) 322 goto bad; 323 error = smb_t2_request(t2p); 324 if (error) 325 goto bad; 326 mdp = &t2p->t2_rparam; 327 if (mdp->md_top) { 328 len = m_fixhdr(mdp->md_top); 329 if (len > dp->ioc_rparamcnt) { 330 error = EMSGSIZE; 331 goto bad; 332 } 333 dp->ioc_rparamcnt = len; 334 error = md_get_mem(mdp, dp->ioc_rparam, len, MB_MUSER); 335 if (error) 336 goto bad; 337 } else 338 dp->ioc_rparamcnt = 0; 339 mdp = &t2p->t2_rdata; 340 if (mdp->md_top) { 341 len = m_fixhdr(mdp->md_top); 342 if (len > dp->ioc_rdatacnt) { 343 error = EMSGSIZE; 344 goto bad; 345 } 346 dp->ioc_rdatacnt = len; 347 error = md_get_mem(mdp, dp->ioc_rdata, len, MB_MUSER); 348 } else 349 dp->ioc_rdatacnt = 0; 350 bad: 351 if (t2p->t_name) 352 smb_strfree(t2p->t_name); 353 smb_t2_done(t2p); 354 return error; 355 } 356