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