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; /* XXX */ 131 struct smb_sharespec sspec, *sspecp = NULL; /* XXX */ 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 *rqp; 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 rqp = malloc(sizeof(struct smb_rq), M_SMBTEMP, M_WAITOK); 235 error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred); 236 if (error) { 237 free(rqp, M_SMBTEMP); 238 return error; 239 } 240 mbp = &rqp->sr_rq; 241 smb_rq_wstart(rqp); 242 error = mb_put_mem(mbp, dp->ioc_twords, dp->ioc_twc * 2, MB_MUSER); 243 if (error) 244 goto bad; 245 smb_rq_wend(rqp); 246 smb_rq_bstart(rqp); 247 error = mb_put_mem(mbp, dp->ioc_tbytes, dp->ioc_tbc, MB_MUSER); 248 if (error) 249 goto bad; 250 smb_rq_bend(rqp); 251 error = smb_rq_simple(rqp); 252 if (error) 253 goto bad; 254 mdp = &rqp->sr_rp; 255 md_get_uint8(mdp, &wc); 256 dp->ioc_rwc = wc; 257 wc *= 2; 258 if (wc > dp->ioc_rpbufsz) { 259 error = EBADRPC; 260 goto bad; 261 } 262 error = md_get_mem(mdp, dp->ioc_rpbuf, wc, MB_MUSER); 263 if (error) 264 goto bad; 265 md_get_uint16le(mdp, &bc); 266 if ((wc + bc) > dp->ioc_rpbufsz) { 267 error = EBADRPC; 268 goto bad; 269 } 270 dp->ioc_rbc = bc; 271 error = md_get_mem(mdp, dp->ioc_rpbuf + wc, bc, MB_MUSER); 272 bad: 273 dp->ioc_errclass = rqp->sr_errclass; 274 dp->ioc_serror = rqp->sr_serror; 275 dp->ioc_error = rqp->sr_error; 276 smb_rq_done(rqp); 277 free(rqp, M_SMBTEMP); 278 return error; 279 280 } 281 282 static int 283 smb_cpdatain(struct mbchain *mbp, int len, caddr_t data) 284 { 285 int error; 286 287 if (len == 0) 288 return 0; 289 error = mb_init(mbp); 290 if (error) 291 return error; 292 return mb_put_mem(mbp, data, len, MB_MUSER); 293 } 294 295 int 296 smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *dp, 297 struct smb_cred *scred) 298 { 299 struct smb_t2rq *t2p; 300 struct mdchain *mdp; 301 int error, len; 302 303 if (dp->ioc_setupcnt > 3) 304 return EINVAL; 305 t2p = malloc(sizeof(struct smb_t2rq), M_SMBTEMP, M_WAITOK); 306 error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup[0], scred); 307 if (error) { 308 free(t2p, M_SMBTEMP); 309 return error; 310 } 311 len = t2p->t2_setupcount = dp->ioc_setupcnt; 312 if (len > 1) 313 t2p->t2_setupdata = dp->ioc_setup; 314 if (dp->ioc_name) { 315 t2p->t_name = smb_strdupin(dp->ioc_name, 128); 316 if (t2p->t_name == NULL) { 317 error = ENOMEM; 318 goto bad; 319 } 320 } 321 t2p->t2_maxscount = 0; 322 t2p->t2_maxpcount = dp->ioc_rparamcnt; 323 t2p->t2_maxdcount = dp->ioc_rdatacnt; 324 error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt, dp->ioc_tparam); 325 if (error) 326 goto bad; 327 error = smb_cpdatain(&t2p->t2_tdata, dp->ioc_tdatacnt, dp->ioc_tdata); 328 if (error) 329 goto bad; 330 error = smb_t2_request(t2p); 331 if (error) 332 goto bad; 333 mdp = &t2p->t2_rparam; 334 if (mdp->md_top) { 335 len = m_fixhdr(mdp->md_top); 336 if (len > dp->ioc_rparamcnt) { 337 error = EMSGSIZE; 338 goto bad; 339 } 340 dp->ioc_rparamcnt = len; 341 error = md_get_mem(mdp, dp->ioc_rparam, len, MB_MUSER); 342 if (error) 343 goto bad; 344 } else 345 dp->ioc_rparamcnt = 0; 346 mdp = &t2p->t2_rdata; 347 if (mdp->md_top) { 348 len = m_fixhdr(mdp->md_top); 349 if (len > dp->ioc_rdatacnt) { 350 error = EMSGSIZE; 351 goto bad; 352 } 353 dp->ioc_rdatacnt = len; 354 error = md_get_mem(mdp, dp->ioc_rdata, len, MB_MUSER); 355 } else 356 dp->ioc_rdatacnt = 0; 357 bad: 358 if (t2p->t_name) 359 smb_strfree(t2p->t_name); 360 smb_t2_done(t2p); 361 free(t2p, M_SMBTEMP); 362 return error; 363 } 364