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 * $Id: smb_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $ 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 #include <sys/param.h> 38 #include <sys/kmem.h> 39 #include <sys/systm.h> 40 #include <sys/policy.h> 41 #include <sys/conf.h> 42 #include <sys/proc.h> 43 #include <sys/fcntl.h> 44 #include <sys/socket.h> 45 #include <sys/cmn_err.h> 46 47 #ifdef APPLE 48 #include <sys/smb_apple.h> 49 #include <sys/smb_iconv.h> 50 #else 51 #include <netsmb/smb_osdep.h> 52 #endif 53 54 #include <netsmb/smb.h> 55 #include <netsmb/smb_conn.h> 56 #include <netsmb/smb_rq.h> 57 #include <netsmb/smb_subr.h> 58 #include <netsmb/smb_dev.h> 59 60 /* 61 * helpers for nsmb device. Can be moved to the smb_dev.c file. 62 */ 63 static void smb_usr_vcspec_free(struct smb_vcspec *spec); 64 65 /* 66 * Moved the access checks here, just becuase 67 * this was a more convenient place to do it 68 * than in every function calling this. 69 */ 70 static int 71 smb_usr_ioc2vcspec(struct smbioc_ossn *dp, struct smb_vcspec *spec) 72 { 73 cred_t *cr = CRED(); 74 uid_t realuid; 75 76 /* 77 * Only superuser can specify a UID or GID. 78 */ 79 realuid = crgetruid(cr); 80 if (dp->ioc_owner == SMBM_ANY_OWNER) 81 spec->owner = realuid; 82 else { 83 /* 84 * Do we have the privilege to create with the 85 * specified uid? (does uid == cr->cr_uid, etc.) 86 * MacOS would want suser(), or similar here. 87 */ 88 if (secpolicy_vnode_owner(cr, dp->ioc_owner)) 89 return (EPERM); 90 spec->owner = dp->ioc_owner; 91 } 92 if (dp->ioc_group == SMBM_ANY_GROUP) 93 spec->group = crgetgid(cr); 94 else { 95 /* 96 * Do we have the privilege to create with the 97 * specified gid? (one of our groups?) 98 */ 99 if (groupmember(dp->ioc_group, cr) || 100 secpolicy_vnode_create_gid(cr) == 0) 101 spec->group = dp->ioc_group; 102 else 103 return (EPERM); 104 } 105 106 /* 107 * Valid codesets? XXX 108 */ 109 if (dp->ioc_localcs[0] == 0) { 110 spec->localcs = "ISO8859-1"; 111 #ifdef NOTYETRESOLVED 112 SMBERROR("no local charset ? dp->ioc_localcs[0]: %d\n", 113 dp->ioc_localcs[0]); 114 return (EINVAL); 115 #endif 116 } else 117 spec->localcs = spec->localcs; 118 119 /* 120 * Check for valid sa_family. 121 * XXX: Just NetBIOS for now. 122 */ 123 if (dp->ioc_server.sa.sa_family != AF_NETBIOS) 124 return (EINVAL); 125 spec->sap = &dp->ioc_server.sa; 126 127 if (dp->ioc_local.sa.sa_family) { 128 /* If specified, local AF must be the same. */ 129 if (dp->ioc_local.sa.sa_family != 130 dp->ioc_server.sa.sa_family) 131 return (EINVAL); 132 spec->lap = &dp->ioc_local.sa; 133 } 134 135 if (dp->ioc_intok) { 136 spec->tok = smb_memdupin(dp->ioc_intok, dp->ioc_intoklen); 137 if (spec->tok == NULL) 138 return (EFAULT); 139 spec->toklen = dp->ioc_intoklen; 140 } 141 142 spec->srvname = dp->ioc_srvname; 143 spec->pass = dp->ioc_password; 144 spec->domain = dp->ioc_workgroup; 145 spec->username = dp->ioc_user; 146 spec->mode = dp->ioc_mode; 147 spec->rights = dp->ioc_rights; 148 spec->servercs = dp->ioc_servercs; 149 spec->optflags = dp->ioc_opt; 150 151 return (0); 152 } 153 154 static void 155 smb_usr_shspec_free(struct smb_sharespec *sspec) 156 { 157 kmem_free(sspec, sizeof (struct smb_sharespec)); 158 } 159 160 static void 161 smb_usr_vcspec_free(struct smb_vcspec *spec) 162 { 163 164 if (spec->tok) { 165 kmem_free(spec->tok, spec->toklen); 166 } 167 kmem_free(spec, sizeof (*spec)); 168 } 169 170 static int 171 smb_usr_ioc2sharespec(struct smbioc_oshare *dp, struct smb_sharespec *spec) 172 { 173 bzero(spec, sizeof (*spec)); 174 spec->name = dp->ioc_share; 175 spec->pass = dp->ioc_password; 176 spec->mode = dp->ioc_mode; 177 spec->rights = dp->ioc_rights; 178 spec->owner = dp->ioc_owner; 179 spec->group = dp->ioc_group; 180 spec->stype = dp->ioc_stype; 181 spec->optflags = dp->ioc_opt; 182 return (0); 183 } 184 185 int 186 smb_usr_findvc(struct smbioc_lookup *dp, struct smb_cred *scred, 187 struct smb_vc **vcpp) 188 { 189 struct smb_vc *vcp = NULL; 190 struct smb_vcspec *vspec = NULL; 191 int error = 0; 192 193 if (dp->ioc_flags & SMBLK_CREATE) 194 return (EINVAL); 195 if (dp->ioc_level != SMBL_VC) 196 return (EINVAL); 197 vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP); 198 error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec); 199 if (error) 200 goto out; 201 error = smb_sm_findvc(vspec, scred, &vcp); 202 if (error == 0) 203 *vcpp = vcp; 204 out: 205 smb_usr_vcspec_free(vspec); 206 return (error); 207 } 208 209 int 210 smb_usr_negotiate(struct smbioc_lookup *dp, struct smb_cred *scred, 211 struct smb_vc **vcpp) 212 { 213 struct smb_vc *vcp = NULL; 214 struct smb_vcspec *vspec = NULL; 215 struct smb_sharespec *sspecp = NULL; 216 int error = 0; 217 218 if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE) 219 return (EINVAL); 220 vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP); 221 error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec); 222 if (error) 223 return (error); 224 if (dp->ioc_flags & SMBLK_CREATE) 225 vspec->optflags |= SMBVOPT_CREATE; 226 if (dp->ioc_level >= SMBL_SHARE) { 227 sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP); 228 error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp); 229 if (error) 230 goto out; 231 } 232 error = smb_sm_negotiate(vspec, scred, &vcp); 233 if (error == 0) { 234 *vcpp = vcp; 235 /* 236 * Used to copyout ioc_outtok, outtoklen here, 237 * but that's now in smb_dev. (our caller) 238 * 239 * If this call asked for extended security and 240 * the server does not support it, clear the 241 * flag so the caller knows this. 242 * 243 * XXX: Should just add sv_caps to ioc_ssn, 244 * set the new sv_caps field here, and let 245 * let the copyout of ioc_ssn handle it. 246 */ 247 if (!(vcp->vc_sopt.sv_caps & SMB_CAP_EXT_SECURITY) && 248 (dp->ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC)) { 249 dp->ioc_ssn.ioc_opt &= ~SMBVOPT_EXT_SEC; 250 SMBSDEBUG("turned off extended security"); 251 } 252 } 253 out: 254 smb_usr_vcspec_free(vspec); 255 smb_usr_shspec_free(sspecp); 256 return (error); 257 } 258 259 int 260 smb_usr_ssnsetup(struct smbioc_lookup *dp, struct smb_cred *scred, 261 struct smb_vc *vcp) 262 { 263 struct smb_vcspec *vspec = NULL; 264 int error; 265 266 if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE) 267 return (EINVAL); 268 269 vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP); 270 error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec); 271 if (error) 272 goto out; 273 274 error = smb_sm_ssnsetup(vspec, scred, vcp); 275 /* 276 * Moved the copyout of ioc_outtok to 277 * smb_dev.c (our caller) 278 */ 279 280 out: 281 smb_usr_vcspec_free(vspec); 282 return (error); 283 } 284 285 286 int 287 smb_usr_tcon(struct smbioc_lookup *dp, struct smb_cred *scred, 288 struct smb_vc *vcp, struct smb_share **sspp) 289 { 290 struct smb_sharespec *sspecp = NULL; 291 int error; 292 293 if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE) 294 return (EINVAL); 295 296 if (dp->ioc_level >= SMBL_SHARE) { 297 sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP); 298 error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp); 299 if (error) 300 goto out; 301 } 302 error = smb_sm_tcon(sspecp, scred, vcp, sspp); 303 304 out: 305 if (sspecp) 306 smb_usr_shspec_free(sspecp); 307 308 return (error); 309 } 310 311 /* 312 * Connect to the resource specified by smbioc_ossn structure. 313 * It may either find an existing connection or try to establish a new one. 314 * If no errors occured smb_vc returned locked and referenced. 315 */ 316 317 int 318 smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp, 319 struct smb_cred *scred) 320 { 321 struct smb_rq rq, *rqp = &rq; 322 struct mbchain *mbp; 323 struct mdchain *mdp; 324 char *p; 325 size_t wc2; 326 u_int8_t wc; 327 u_int16_t bc; 328 int error; 329 330 switch (dp->ioc_cmd) { 331 case SMB_COM_TRANSACTION2: 332 case SMB_COM_TRANSACTION2_SECONDARY: 333 case SMB_COM_CLOSE_AND_TREE_DISC: 334 case SMB_COM_TREE_CONNECT: 335 case SMB_COM_TREE_DISCONNECT: 336 case SMB_COM_NEGOTIATE: 337 case SMB_COM_SESSION_SETUP_ANDX: 338 case SMB_COM_LOGOFF_ANDX: 339 case SMB_COM_TREE_CONNECT_ANDX: 340 return (EPERM); 341 } 342 error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred); 343 if (error) 344 return (error); 345 mbp = &rqp->sr_rq; 346 smb_rq_wstart(rqp); 347 error = mb_put_mem(mbp, dp->ioc_twords, 348 dp->ioc_twc * 2, MB_MUSER); 349 if (error) 350 goto bad; 351 smb_rq_wend(rqp); 352 smb_rq_bstart(rqp); 353 error = mb_put_mem(mbp, dp->ioc_tbytes, 354 dp->ioc_tbc, MB_MUSER); 355 if (error) 356 goto bad; 357 smb_rq_bend(rqp); 358 error = smb_rq_simple(rqp); 359 if (error) 360 goto bad; 361 mdp = &rqp->sr_rp; 362 md_get_uint8(mdp, &wc); 363 dp->ioc_rwc = wc; 364 wc2 = wc * 2; 365 if (wc2 > dp->ioc_rpbufsz) { 366 error = EBADRPC; 367 goto bad; 368 } 369 error = md_get_mem(mdp, dp->ioc_rpbuf, wc2, MB_MUSER); 370 if (error) 371 goto bad; 372 md_get_uint16le(mdp, &bc); 373 if ((wc2 + bc) > dp->ioc_rpbufsz) { 374 error = EBADRPC; 375 goto bad; 376 } 377 dp->ioc_rbc = bc; 378 p = dp->ioc_rpbuf; 379 error = md_get_mem(mdp, p + wc2, bc, MB_MUSER); 380 bad: 381 dp->ioc_errclass = rqp->sr_errclass; 382 dp->ioc_serror = rqp->sr_serror; 383 dp->ioc_error = rqp->sr_error; 384 smb_rq_done(rqp); 385 return (error); 386 387 } 388 389 static int 390 smb_cpdatain(struct mbchain *mbp, int len, char *data) 391 { 392 int error; 393 394 if (len == 0) 395 return (0); 396 error = mb_init(mbp); 397 if (error) 398 return (error); 399 return (mb_put_mem(mbp, data, len, MB_MUSER)); 400 } 401 402 int 403 smb_usr_t2request(struct smb_share *ssp, smbioc_t2rq_t *dp, 404 struct smb_cred *scred) 405 { 406 struct smb_t2rq t2, *t2p = &t2; 407 struct mdchain *mdp; 408 int error, len; 409 410 if (dp->ioc_setupcnt > SMB_MAXSETUPWORDS) 411 return (EINVAL); 412 413 t2p = (struct smb_t2rq *)kmem_alloc(sizeof (struct smb_t2rq), KM_SLEEP); 414 if (t2p == NULL) 415 return (ENOMEM); 416 error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup, dp->ioc_setupcnt, 417 scred); 418 if (error) 419 return (error); 420 len = t2p->t2_setupcount = dp->ioc_setupcnt; 421 if (len > 1) 422 t2p->t2_setupdata = dp->ioc_setup; 423 if (dp->ioc_name) { 424 bcopy(dp->ioc_name, t2p->t_name, 128); 425 if (t2p->t_name == NULL) { 426 error = ENOMEM; 427 goto bad; 428 } 429 } 430 t2p->t2_maxscount = 0; 431 t2p->t2_maxpcount = dp->ioc_rparamcnt; 432 t2p->t2_maxdcount = dp->ioc_rdatacnt; 433 error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt, 434 dp->ioc_tparam); 435 if (error) 436 goto bad; 437 error = smb_cpdatain(&t2p->t2_tdata, 438 dp->ioc_tdatacnt, dp->ioc_tdata); 439 if (error) 440 goto bad; 441 error = smb_t2_request(t2p); 442 dp->ioc_errclass = t2p->t2_sr_errclass; 443 dp->ioc_serror = t2p->t2_sr_serror; 444 dp->ioc_error = t2p->t2_sr_error; 445 dp->ioc_rpflags2 = t2p->t2_sr_rpflags2; 446 if (error) 447 goto bad; 448 mdp = &t2p->t2_rparam; 449 if (mdp->md_top) { 450 mblk_t *m = mdp->md_top; 451 #ifdef lint 452 m = m; 453 #endif 454 len = m_fixhdr(mdp->md_top); 455 if (len > dp->ioc_rparamcnt) { 456 error = EMSGSIZE; 457 goto bad; 458 } 459 dp->ioc_rparamcnt = (ushort_t)len; 460 error = md_get_mem(mdp, dp->ioc_rparam, 461 len, MB_MUSER); 462 if (error) { 463 goto bad; 464 } 465 } else 466 dp->ioc_rparamcnt = 0; 467 mdp = &t2p->t2_rdata; 468 if (mdp->md_top) { 469 mblk_t *m = mdp->md_top; 470 #ifdef lint 471 m = m; 472 #endif 473 len = m_fixhdr(mdp->md_top); 474 if (len > dp->ioc_rdatacnt) { 475 error = EMSGSIZE; 476 goto bad; 477 } 478 dp->ioc_rdatacnt = (ushort_t)len; 479 error = md_get_mem(mdp, dp->ioc_rdata, 480 len, MB_MUSER); 481 if (error) { 482 goto bad; 483 } 484 } else 485 dp->ioc_rdatacnt = 0; 486 bad: 487 smb_t2_done(t2p); 488 return (error); 489 } 490 491 /* 492 * Helper for nsmb_ioctl cases 493 * SMBIOC_READ, SMBIOC_WRITE 494 */ 495 int 496 smb_usr_rw(struct smb_share *ssp, smbioc_rw_t *rwrq, 497 int cmd, struct smb_cred *scred) 498 { 499 struct iovec aiov[1]; 500 struct uio auio; 501 u_int16_t fh; 502 int error; 503 uio_rw_t rw; 504 505 switch (cmd) { 506 case SMBIOC_READ: 507 rw = UIO_READ; 508 break; 509 case SMBIOC_WRITE: 510 rw = UIO_WRITE; 511 break; 512 default: 513 return (ENODEV); 514 } 515 516 fh = htoles(rwrq->ioc_fh); 517 518 aiov[0].iov_base = rwrq->ioc_base; 519 aiov[0].iov_len = (size_t)rwrq->ioc_cnt; 520 521 auio.uio_iov = aiov; 522 auio.uio_iovcnt = 1; 523 auio.uio_loffset = rwrq->ioc_offset; 524 auio.uio_segflg = UIO_USERSPACE; 525 auio.uio_fmode = 0; 526 auio.uio_resid = (size_t)rwrq->ioc_cnt; 527 528 error = smb_rwuio(ssp, fh, rw, &auio, scred, 0); 529 530 /* 531 * On return ioc_cnt holds the 532 * number of bytes transferred. 533 */ 534 rwrq->ioc_cnt -= auio.uio_resid; 535 536 return (error); 537 } 538