1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/malloc.h> 34 #include <sys/kernel.h> 35 #include <sys/systm.h> 36 #include <sys/conf.h> 37 #include <sys/proc.h> 38 #include <sys/fcntl.h> 39 #include <sys/socket.h> 40 #include <sys/socketvar.h> 41 #include <sys/sysctl.h> 42 #include <sys/mbuf.h> 43 44 #include <sys/iconv.h> 45 46 #include <netsmb/smb.h> 47 #include <netsmb/smb_conn.h> 48 #include <netsmb/smb_rq.h> 49 #include <netsmb/smb_subr.h> 50 #include <netsmb/smb_dev.h> 51 52 /* 53 * helpers for nsmb device. Can be moved to the smb_dev.c file. 54 */ 55 static void smb_usr_vcspec_free(struct smb_vcspec *spec); 56 57 static int 58 smb_usr_vc2spec(struct smbioc_ossn *dp, struct smb_vcspec *spec) 59 { 60 int flags = 0; 61 62 bzero(spec, sizeof(*spec)); 63 64 #ifdef NETSMB_NO_ANON_USER 65 if (dp->ioc_user[0] == 0) 66 return EINVAL; 67 #endif 68 69 if (dp->ioc_server == NULL) 70 return EINVAL; 71 if (dp->ioc_localcs[0] == 0) { 72 SMBERROR("no local charset ?\n"); 73 return EINVAL; 74 } 75 76 spec->sap = smb_memdupin(dp->ioc_server, dp->ioc_svlen); 77 if (spec->sap == NULL) 78 return ENOMEM; 79 if (dp->ioc_local) { 80 spec->lap = smb_memdupin(dp->ioc_local, dp->ioc_lolen); 81 if (spec->lap == NULL) { 82 smb_usr_vcspec_free(spec); 83 return ENOMEM; 84 } 85 } 86 spec->srvname = dp->ioc_srvname; 87 spec->pass = dp->ioc_password; 88 spec->domain = dp->ioc_workgroup; 89 spec->username = dp->ioc_user; 90 spec->mode = dp->ioc_mode; 91 spec->rights = dp->ioc_rights; 92 spec->owner = dp->ioc_owner; 93 spec->group = dp->ioc_group; 94 spec->localcs = dp->ioc_localcs; 95 spec->servercs = dp->ioc_servercs; 96 if (dp->ioc_opt & SMBVOPT_PRIVATE) 97 flags |= SMBV_PRIVATE; 98 if (dp->ioc_opt & SMBVOPT_SINGLESHARE) 99 flags |= SMBV_PRIVATE | SMBV_SINGLESHARE; 100 spec->flags = flags; 101 return 0; 102 } 103 104 static void 105 smb_usr_vcspec_free(struct smb_vcspec *spec) 106 { 107 if (spec->sap) 108 smb_memfree(spec->sap); 109 if (spec->lap) 110 smb_memfree(spec->lap); 111 } 112 113 static int 114 smb_usr_share2spec(struct smbioc_oshare *dp, struct smb_sharespec *spec) 115 { 116 bzero(spec, sizeof(*spec)); 117 spec->mode = dp->ioc_mode; 118 spec->rights = dp->ioc_rights; 119 spec->owner = dp->ioc_owner; 120 spec->group = dp->ioc_group; 121 spec->name = dp->ioc_share; 122 spec->stype = dp->ioc_stype; 123 spec->pass = dp->ioc_password; 124 return 0; 125 } 126 127 int 128 smb_usr_lookup(struct smbioc_lookup *dp, struct smb_cred *scred, 129 struct smb_vc **vcpp, struct smb_share **sspp) 130 { 131 struct smb_vc *vcp = NULL; 132 struct smb_vcspec vspec; /* XXX */ 133 struct smb_sharespec sspec, *sspecp = NULL; /* XXX */ 134 int error; 135 136 if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE) 137 return EINVAL; 138 error = smb_usr_vc2spec(&dp->ioc_ssn, &vspec); 139 if (error) 140 return error; 141 if (dp->ioc_flags & SMBLK_CREATE) 142 vspec.flags |= SMBV_CREATE; 143 144 if (dp->ioc_level >= SMBL_SHARE) { 145 error = smb_usr_share2spec(&dp->ioc_sh, &sspec); 146 if (error) 147 goto out; 148 sspecp = &sspec; 149 } 150 error = smb_sm_lookup(&vspec, sspecp, scred, &vcp); 151 if (error == 0) { 152 *vcpp = vcp; 153 *sspp = vspec.ssp; 154 } 155 out: 156 smb_usr_vcspec_free(&vspec); 157 return error; 158 } 159 160 /* 161 * Connect to the resource specified by smbioc_ossn structure. 162 * It may either find an existing connection or try to establish a new one. 163 * If no errors occurred smb_vc returned locked and referenced. 164 */ 165 int 166 smb_usr_opensession(struct smbioc_ossn *dp, struct smb_cred *scred, 167 struct smb_vc **vcpp) 168 { 169 struct smb_vc *vcp = NULL; 170 struct smb_vcspec vspec; 171 int error; 172 173 error = smb_usr_vc2spec(dp, &vspec); 174 if (error) 175 return error; 176 if (dp->ioc_opt & SMBVOPT_CREATE) 177 vspec.flags |= SMBV_CREATE; 178 179 error = smb_sm_lookup(&vspec, NULL, scred, &vcp); 180 smb_usr_vcspec_free(&vspec); 181 return error; 182 } 183 184 int 185 smb_usr_openshare(struct smb_vc *vcp, struct smbioc_oshare *dp, 186 struct smb_cred *scred, struct smb_share **sspp) 187 { 188 struct smb_share *ssp; 189 struct smb_sharespec shspec; 190 int error; 191 192 error = smb_usr_share2spec(dp, &shspec); 193 if (error) 194 return error; 195 error = smb_vc_lookupshare(vcp, &shspec, scred, &ssp); 196 if (error == 0) { 197 *sspp = ssp; 198 return 0; 199 } 200 if ((dp->ioc_opt & SMBSOPT_CREATE) == 0) 201 return error; 202 error = smb_share_create(vcp, &shspec, scred, &ssp); 203 if (error) 204 return error; 205 error = smb_smb_treeconnect(ssp, scred); 206 if (error) { 207 smb_share_put(ssp, scred); 208 } else 209 *sspp = ssp; 210 return error; 211 } 212 213 int 214 smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp, 215 struct smb_cred *scred) 216 { 217 struct smb_rq *rqp; 218 struct mbchain *mbp; 219 struct mdchain *mdp; 220 u_int8_t wc; 221 u_int16_t bc; 222 int error; 223 224 switch (dp->ioc_cmd) { 225 case SMB_COM_TRANSACTION2: 226 case SMB_COM_TRANSACTION2_SECONDARY: 227 case SMB_COM_CLOSE_AND_TREE_DISC: 228 case SMB_COM_TREE_CONNECT: 229 case SMB_COM_TREE_DISCONNECT: 230 case SMB_COM_NEGOTIATE: 231 case SMB_COM_SESSION_SETUP_ANDX: 232 case SMB_COM_LOGOFF_ANDX: 233 case SMB_COM_TREE_CONNECT_ANDX: 234 return EPERM; 235 } 236 rqp = malloc(sizeof(struct smb_rq), M_SMBTEMP, M_WAITOK); 237 error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred); 238 if (error) { 239 free(rqp, M_SMBTEMP); 240 return error; 241 } 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); 274 bad: 275 dp->ioc_errclass = rqp->sr_errclass; 276 dp->ioc_serror = rqp->sr_serror; 277 dp->ioc_error = rqp->sr_error; 278 smb_rq_done(rqp); 279 free(rqp, M_SMBTEMP); 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 *t2p; 302 struct mdchain *mdp; 303 int error, len; 304 305 if (dp->ioc_setupcnt > 3) 306 return EINVAL; 307 t2p = malloc(sizeof(struct smb_t2rq), M_SMBTEMP, M_WAITOK); 308 error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup[0], scred); 309 if (error) { 310 free(t2p, M_SMBTEMP); 311 return error; 312 } 313 len = t2p->t2_setupcount = dp->ioc_setupcnt; 314 if (len > 1) 315 t2p->t2_setupdata = dp->ioc_setup; 316 if (dp->ioc_name) { 317 t2p->t_name = smb_strdupin(dp->ioc_name, 128); 318 if (t2p->t_name == NULL) { 319 error = ENOMEM; 320 goto bad; 321 } 322 } 323 t2p->t2_maxscount = 0; 324 t2p->t2_maxpcount = dp->ioc_rparamcnt; 325 t2p->t2_maxdcount = dp->ioc_rdatacnt; 326 error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt, dp->ioc_tparam); 327 if (error) 328 goto bad; 329 error = smb_cpdatain(&t2p->t2_tdata, dp->ioc_tdatacnt, dp->ioc_tdata); 330 if (error) 331 goto bad; 332 error = smb_t2_request(t2p); 333 if (error) 334 goto bad; 335 mdp = &t2p->t2_rparam; 336 if (mdp->md_top) { 337 len = m_fixhdr(mdp->md_top); 338 if (len > dp->ioc_rparamcnt) { 339 error = EMSGSIZE; 340 goto bad; 341 } 342 dp->ioc_rparamcnt = len; 343 error = md_get_mem(mdp, dp->ioc_rparam, len, MB_MUSER); 344 if (error) 345 goto bad; 346 } else 347 dp->ioc_rparamcnt = 0; 348 mdp = &t2p->t2_rdata; 349 if (mdp->md_top) { 350 len = m_fixhdr(mdp->md_top); 351 if (len > dp->ioc_rdatacnt) { 352 error = EMSGSIZE; 353 goto bad; 354 } 355 dp->ioc_rdatacnt = len; 356 error = md_get_mem(mdp, dp->ioc_rdata, len, MB_MUSER); 357 } else 358 dp->ioc_rdatacnt = 0; 359 bad: 360 if (t2p->t_name) 361 smb_strfree(t2p->t_name); 362 smb_t2_done(t2p); 363 free(t2p, M_SMBTEMP); 364 return error; 365 } 366