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 /* 36 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 37 * Use is subject to license terms. 38 * 39 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 40 */ 41 42 #include <sys/param.h> 43 #include <sys/kmem.h> 44 #include <sys/systm.h> 45 #include <sys/policy.h> 46 #include <sys/conf.h> 47 #include <sys/proc.h> 48 #include <sys/fcntl.h> 49 #include <sys/file.h> 50 #include <sys/socket.h> 51 #include <sys/sunddi.h> 52 #include <sys/cmn_err.h> 53 54 #include <netsmb/smb_osdep.h> 55 56 #include <netsmb/smb.h> 57 #include <netsmb/smb_conn.h> 58 #include <netsmb/smb_rq.h> 59 #include <netsmb/smb_subr.h> 60 #include <netsmb/smb_dev.h> 61 62 static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg); 63 64 /* 65 * Ioctl function for SMBIOC_GETSSNKEY 66 * Size copied out is SMBIOC_HASH_SZ. 67 * 68 * The RPC library needs this for encrypting things 69 * like "set password" requests. This is called 70 * with an active RPC binding, so the connection 71 * will already be active (but this checks). 72 */ 73 int 74 smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags) 75 { 76 struct smb_vc *vcp = NULL; 77 78 /* This ioctl requires an active session. */ 79 if ((vcp = sdp->sd_vc) == NULL) 80 return (ENOTCONN); 81 if (vcp->vc_state != SMBIOD_ST_VCACTIVE) 82 return (ENOTCONN); 83 84 /* 85 * Return the session key. 86 */ 87 if (vcp->vc_ssnkey == NULL || 88 vcp->vc_ssnkeylen < SMBIOC_HASH_SZ) 89 return (EINVAL); 90 if (ddi_copyout(vcp->vc_ssnkey, (void *)arg, 91 SMBIOC_HASH_SZ, flags)) 92 return (EFAULT); 93 94 return (0); 95 } 96 97 /* 98 * Ioctl function for SMBIOC_XACTNP (transact named pipe) 99 */ 100 int 101 smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 102 { 103 struct smb_cred scred; 104 struct smb_share *ssp; 105 smbioc_xnp_t *ioc = NULL; 106 struct smb_t2rq *t2p = NULL; 107 struct mdchain *mdp; 108 int err, len, mbseg; 109 uint16_t setup[2]; 110 111 /* This ioctl requires a share. */ 112 if ((ssp = sdp->sd_share) == NULL) 113 return (ENOTCONN); 114 115 smb_credinit(&scred, cr); 116 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 117 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 118 err = EFAULT; 119 goto out; 120 } 121 122 /* See ddi_copyin, ddi_copyout */ 123 mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER; 124 125 /* 126 * Fill in the FID for libsmbfs transact named pipe. 127 */ 128 if (ioc->ioc_fh == -1) { 129 if (sdp->sd_vcgenid != ssp->ss_vcgenid) { 130 err = ESTALE; 131 goto out; 132 } 133 ioc->ioc_fh = sdp->sd_smbfid; 134 } 135 136 setup[0] = TRANS_TRANSACT_NAMED_PIPE; 137 setup[1] = (uint16_t)ioc->ioc_fh; 138 139 t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP); 140 err = smb_t2_init(t2p, SSTOCP(ssp), setup, 2, &scred); 141 if (err) 142 goto out; 143 t2p->t2_setupcount = 2; 144 t2p->t2_setupdata = setup; 145 146 t2p->t_name = "\\PIPE\\"; 147 t2p->t_name_len = 6; 148 149 t2p->t2_maxscount = 0; 150 t2p->t2_maxpcount = 0; 151 t2p->t2_maxdcount = ioc->ioc_rdlen; 152 153 /* Transmit parameters (none) */ 154 155 /* Transmit data */ 156 err = smb_cpdatain(&t2p->t2_tdata, 157 ioc->ioc_tdlen, ioc->ioc_tdata, mbseg); 158 if (err) 159 goto out; 160 161 err = smb_t2_request(t2p); 162 163 /* No returned parameters. */ 164 165 /* Copyout returned data. */ 166 mdp = &t2p->t2_rdata; 167 if (err == 0 && mdp->md_top != NULL) { 168 /* User's buffer large enough? */ 169 len = m_fixhdr(mdp->md_top); 170 if (len > ioc->ioc_rdlen) { 171 err = EMSGSIZE; 172 goto out; 173 } 174 ioc->ioc_rdlen = (ushort_t)len; 175 err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg); 176 if (err) 177 goto out; 178 } else 179 ioc->ioc_rdlen = 0; 180 181 if (t2p->t2_sr_error == NT_STATUS_BUFFER_OVERFLOW) 182 ioc->ioc_more = 1; 183 184 (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); 185 186 187 out: 188 if (t2p != NULL) { 189 /* Note: t2p->t_name no longer allocated */ 190 smb_t2_done(t2p); 191 kmem_free(t2p, sizeof (*t2p)); 192 } 193 kmem_free(ioc, sizeof (*ioc)); 194 smb_credrele(&scred); 195 196 return (err); 197 } 198 199 /* helper for _t2request */ 200 static int 201 smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg) 202 { 203 int error; 204 205 if (len == 0) 206 return (0); 207 error = mb_init(mbp); 208 if (error) 209 return (error); 210 return (mb_put_mem(mbp, data, len, mbseg)); 211 } 212 213 /* 214 * Helper for nsmb_ioctl cases 215 * SMBIOC_READ, SMBIOC_WRITE 216 */ 217 int 218 smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 219 { 220 struct smb_cred scred; 221 struct smb_share *ssp; 222 smbioc_rw_t *ioc = NULL; 223 struct iovec aiov[1]; 224 struct uio auio; 225 uint16_t fh; 226 int err; 227 uio_rw_t rw; 228 229 /* This ioctl requires a share. */ 230 if ((ssp = sdp->sd_share) == NULL) 231 return (ENOTCONN); 232 233 /* After reconnect, force close+reopen */ 234 if (sdp->sd_vcgenid != ssp->ss_vcgenid) 235 return (ESTALE); 236 237 smb_credinit(&scred, cr); 238 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 239 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 240 err = EFAULT; 241 goto out; 242 } 243 244 switch (cmd) { 245 case SMBIOC_READ: 246 rw = UIO_READ; 247 break; 248 case SMBIOC_WRITE: 249 rw = UIO_WRITE; 250 break; 251 default: 252 err = ENODEV; 253 goto out; 254 } 255 256 /* 257 * If caller passes -1 in ioc_fh, then 258 * use the FID from SMBIOC_NTCREATE. 259 */ 260 if (ioc->ioc_fh == -1) 261 fh = (uint16_t)sdp->sd_smbfid; 262 else 263 fh = (uint16_t)ioc->ioc_fh; 264 265 aiov[0].iov_base = ioc->ioc_base; 266 aiov[0].iov_len = (size_t)ioc->ioc_cnt; 267 268 auio.uio_iov = aiov; 269 auio.uio_iovcnt = 1; 270 auio.uio_loffset = ioc->ioc_offset; 271 auio.uio_segflg = (flags & FKIOCTL) ? 272 UIO_SYSSPACE : UIO_USERSPACE; 273 auio.uio_fmode = 0; 274 auio.uio_resid = (size_t)ioc->ioc_cnt; 275 276 err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0); 277 278 /* 279 * On return ioc_cnt holds the 280 * number of bytes transferred. 281 */ 282 ioc->ioc_cnt -= auio.uio_resid; 283 284 (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); 285 286 out: 287 kmem_free(ioc, sizeof (*ioc)); 288 smb_credrele(&scred); 289 290 return (err); 291 } 292 293 /* 294 * Helper for nsmb_ioctl case 295 * SMBIOC_NTCREATE 296 */ 297 int 298 smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 299 { 300 struct smb_cred scred; 301 struct mbchain name_mb; 302 struct smb_share *ssp; 303 smbioc_ntcreate_t *ioc = NULL; 304 uint16_t fid; 305 int err, nmlen; 306 307 /* This ioctl requires a share. */ 308 if ((ssp = sdp->sd_share) == NULL) 309 return (ENOTCONN); 310 311 /* Must not be already open. */ 312 if (sdp->sd_smbfid != -1) 313 return (EINVAL); 314 315 mb_init(&name_mb); 316 smb_credinit(&scred, cr); 317 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 318 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 319 err = EFAULT; 320 goto out; 321 } 322 323 /* Build name_mb */ 324 ioc->ioc_name[SMBIOC_MAX_NAME-1] = '\0'; 325 nmlen = strnlen(ioc->ioc_name, SMBIOC_MAX_NAME-1); 326 err = smb_put_dmem(&name_mb, SSTOVC(ssp), 327 ioc->ioc_name, nmlen, 328 SMB_CS_NONE, NULL); 329 if (err != 0) 330 goto out; 331 332 /* Do the OtW open, save the FID. */ 333 err = smb_smb_ntcreate(ssp, &name_mb, 334 0, /* create flags */ 335 ioc->ioc_req_acc, 336 ioc->ioc_efattr, 337 ioc->ioc_share_acc, 338 ioc->ioc_open_disp, 339 ioc->ioc_creat_opts, 340 NTCREATEX_IMPERSONATION_IMPERSONATION, 341 &scred, 342 &fid, 343 NULL, 344 NULL); 345 if (err != 0) 346 goto out; 347 348 sdp->sd_smbfid = fid; 349 sdp->sd_vcgenid = ssp->ss_vcgenid; 350 351 out: 352 kmem_free(ioc, sizeof (*ioc)); 353 smb_credrele(&scred); 354 mb_done(&name_mb); 355 356 return (err); 357 } 358 359 /* 360 * Helper for nsmb_ioctl case 361 * SMBIOC_PRINTJOB 362 */ 363 int 364 smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) 365 { 366 struct smb_cred scred; 367 struct smb_share *ssp; 368 smbioc_printjob_t *ioc = NULL; 369 uint16_t fid; 370 int err; 371 372 /* This ioctl requires a share. */ 373 if ((ssp = sdp->sd_share) == NULL) 374 return (ENOTCONN); 375 376 /* The share must be a print queue. */ 377 if (ssp->ss_type != STYPE_PRINTQ) 378 return (EINVAL); 379 380 /* Must not be already open. */ 381 if (sdp->sd_smbfid != -1) 382 return (EINVAL); 383 384 smb_credinit(&scred, cr); 385 ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP); 386 if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) { 387 err = EFAULT; 388 goto out; 389 } 390 ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0'; 391 392 /* Do the OtW open, save the FID. */ 393 err = smb_smb_open_prjob(ssp, ioc->ioc_title, 394 ioc->ioc_setuplen, ioc->ioc_prmode, 395 &scred, &fid); 396 if (err != 0) 397 goto out; 398 399 sdp->sd_smbfid = fid; 400 sdp->sd_vcgenid = ssp->ss_vcgenid; 401 402 out: 403 kmem_free(ioc, sizeof (*ioc)); 404 smb_credrele(&scred); 405 406 return (err); 407 } 408 409 /* 410 * Helper for nsmb_ioctl case 411 * SMBIOC_CLOSEFH 412 */ 413 int 414 smb_usr_closefh(smb_dev_t *sdp, cred_t *cr) 415 { 416 struct smb_cred scred; 417 struct smb_share *ssp; 418 uint16_t fid; 419 int err; 420 421 /* This ioctl requires a share. */ 422 if ((ssp = sdp->sd_share) == NULL) 423 return (ENOTCONN); 424 425 if (sdp->sd_smbfid == -1) 426 return (0); 427 fid = (uint16_t)sdp->sd_smbfid; 428 sdp->sd_smbfid = -1; 429 430 smb_credinit(&scred, cr); 431 if (ssp->ss_type == STYPE_PRINTQ) 432 err = smb_smb_close_prjob(ssp, fid, &scred); 433 else 434 err = smb_smb_close(ssp, fid, NULL, &scred); 435 smb_credrele(&scred); 436 437 return (err); 438 } 439 440 /* 441 * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE 442 * Find or create a session (a.k.a. "VC" in here) 443 */ 444 int 445 smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 446 { 447 struct smb_cred scred; 448 smbioc_ossn_t *ossn = NULL; 449 struct smb_vc *vcp = NULL; 450 int error = 0; 451 uid_t realuid; 452 453 /* Should be no VC */ 454 if (sdp->sd_vc != NULL) 455 return (EISCONN); 456 457 smb_credinit(&scred, cr); 458 ossn = kmem_alloc(sizeof (*ossn), KM_SLEEP); 459 if (ddi_copyin((void *)arg, ossn, sizeof (*ossn), flags)) { 460 error = EFAULT; 461 goto out; 462 } 463 464 /* 465 * Only superuser can specify a UID or GID. 466 */ 467 realuid = crgetruid(cr); 468 if (ossn->ssn_owner == SMBM_ANY_OWNER) 469 ossn->ssn_owner = realuid; 470 else { 471 /* 472 * Do we have the privilege to create with the 473 * specified uid? (does uid == cr->cr_uid, etc.) 474 */ 475 if (secpolicy_vnode_owner(cr, ossn->ssn_owner)) { 476 error = EPERM; 477 goto out; 478 } 479 /* ossn->ssn_owner is OK */ 480 } 481 482 /* 483 * Make sure the strings are null terminated. 484 */ 485 ossn->ssn_srvname[SMBIOC_MAX_NAME-1] = '\0'; 486 ossn->ssn_id.id_domain[ SMBIOC_MAX_NAME-1] = '\0'; 487 ossn->ssn_id.id_user[ SMBIOC_MAX_NAME-1] = '\0'; 488 489 if (cmd == SMBIOC_SSN_CREATE) 490 ossn->ssn_vopt |= SMBVOPT_CREATE; 491 else /* FIND */ 492 ossn->ssn_vopt &= ~SMBVOPT_CREATE; 493 494 error = smb_vc_findcreate(ossn, &scred, &vcp); 495 if (error) 496 goto out; 497 ASSERT(vcp != NULL); 498 499 /* 500 * We have a VC, held, but not locked. 501 * If we're creating, mark this instance as 502 * an open from IOD so close can do cleanup. 503 * 504 * XXX: Would be nice to have a back pointer 505 * from the VC to this (IOD) sdp instance. 506 */ 507 if (cmd == SMBIOC_SSN_CREATE) { 508 if (vcp->iod_thr != NULL) { 509 error = EEXIST; 510 goto out; 511 } 512 sdp->sd_flags |= NSMBFL_IOD; 513 } else { 514 /* 515 * Wait for it to finish connecting 516 * (or reconnect) if necessary. 517 */ 518 if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { 519 error = smb_iod_reconnect(vcp); 520 if (error != 0) 521 goto out; 522 } 523 } 524 525 /* 526 * The VC has a hold from _findvc 527 * which we keep until _SSN_RELE 528 * or nsmb_close(). 529 */ 530 sdp->sd_level = SMBL_VC; 531 sdp->sd_vc = vcp; 532 vcp = NULL; 533 (void) ddi_copyout(ossn, (void *)arg, sizeof (*ossn), flags); 534 535 out: 536 if (vcp) { 537 /* Error path: rele hold from _findcreate */ 538 smb_vc_rele(vcp); 539 } 540 kmem_free(ossn, sizeof (*ossn)); 541 smb_credrele(&scred); 542 543 return (error); 544 } 545 546 /* 547 * Ioctl functions: SMBIOC_SSN_RELE, SMBIOC_SSN_KILL 548 * Release or kill the current session. 549 */ 550 int 551 smb_usr_drop_ssn(smb_dev_t *sdp, int cmd) 552 { 553 struct smb_vc *vcp = NULL; 554 555 /* Must have a VC. */ 556 if ((vcp = sdp->sd_vc) == NULL) 557 return (ENOTCONN); 558 559 /* If we have a share ref, drop it too. */ 560 if (sdp->sd_share) { 561 smb_share_rele(sdp->sd_share); 562 sdp->sd_share = NULL; 563 sdp->sd_level = SMBL_VC; 564 } 565 566 if (cmd == SMBIOC_SSN_KILL) 567 smb_vc_kill(vcp); 568 569 /* Drop the VC ref. */ 570 smb_vc_rele(vcp); 571 sdp->sd_vc = NULL; 572 sdp->sd_level = 0; 573 574 return (0); 575 } 576 577 /* 578 * Find or create a tree (connected share) 579 */ 580 int 581 smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 582 { 583 struct smb_cred scred; 584 smbioc_tcon_t *tcon = NULL; 585 struct smb_vc *vcp = NULL; 586 struct smb_share *ssp = NULL; 587 int error = 0; 588 589 /* Must have a VC. */ 590 if ((vcp = sdp->sd_vc) == NULL) 591 return (ENOTCONN); 592 /* Should not have a share. */ 593 if (sdp->sd_share != NULL) 594 return (EISCONN); 595 596 smb_credinit(&scred, cr); 597 tcon = kmem_alloc(sizeof (*tcon), KM_SLEEP); 598 if (ddi_copyin((void *)arg, tcon, sizeof (*tcon), flags)) { 599 error = EFAULT; 600 goto out; 601 } 602 603 /* 604 * Make sure the strings are null terminated. 605 */ 606 tcon->tc_sh.sh_name[SMBIOC_MAX_NAME-1] = '\0'; 607 tcon->tc_sh.sh_pass[SMBIOC_MAX_NAME-1] = '\0'; 608 609 if (cmd == SMBIOC_TREE_CONNECT) 610 tcon->tc_opt |= SMBSOPT_CREATE; 611 else /* FIND */ 612 tcon->tc_opt &= ~SMBSOPT_CREATE; 613 614 error = smb_share_findcreate(tcon, vcp, &ssp, &scred); 615 if (error) 616 goto out; 617 ASSERT(ssp != NULL); 618 619 /* 620 * We have a share, held, but not locked. 621 * If we're creating, do tree connect now, 622 * otherwise let that wait for a request. 623 */ 624 if (cmd == SMBIOC_TREE_CONNECT) { 625 error = smb_share_tcon(ssp, &scred); 626 if (error) 627 goto out; 628 } 629 630 /* 631 * Give caller the real share type from 632 * the tree connect response, so they can 633 * see if they got the requested type. 634 */ 635 tcon->tc_sh.sh_type = ssp->ss_type; 636 637 /* 638 * The share has a hold from _tcon 639 * which we keep until nsmb_close() 640 * or the SMBIOC_TDIS below. 641 */ 642 sdp->sd_level = SMBL_SHARE; 643 sdp->sd_share = ssp; 644 ssp = NULL; 645 (void) ddi_copyout(tcon, (void *)arg, sizeof (*tcon), flags); 646 647 out: 648 if (ssp) { 649 /* Error path: rele hold from _findcreate */ 650 smb_share_rele(ssp); 651 } 652 /* 653 * This structure may contain a 654 * cleartext password, so zap it. 655 */ 656 bzero(tcon, sizeof (*tcon)); 657 kmem_free(tcon, sizeof (*tcon)); 658 smb_credrele(&scred); 659 660 return (error); 661 } 662 663 /* 664 * Ioctl functions: SMBIOC_TREE_RELE, SMBIOC_TREE_KILL 665 * Release or kill the current tree 666 */ 667 int 668 smb_usr_drop_tree(smb_dev_t *sdp, int cmd) 669 { 670 struct smb_share *ssp = NULL; 671 672 /* Must have a VC and a share. */ 673 if (sdp->sd_vc == NULL) 674 return (ENOTCONN); 675 if ((ssp = sdp->sd_share) == NULL) 676 return (ENOTCONN); 677 678 if (cmd == SMBIOC_TREE_KILL) 679 smb_share_kill(ssp); 680 681 /* Drop the share ref. */ 682 smb_share_rele(sdp->sd_share); 683 sdp->sd_share = NULL; 684 sdp->sd_level = SMBL_VC; 685 686 return (0); 687 } 688 689 /* 690 * Ioctl handler for all SMBIOC_IOD_... 691 */ 692 int 693 smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 694 { 695 struct smb_vc *vcp; 696 int err = 0; 697 698 /* Must be the IOD. */ 699 if ((sdp->sd_flags & NSMBFL_IOD) == 0) 700 return (EINVAL); 701 /* Must have a VC and no share. */ 702 if ((vcp = sdp->sd_vc) == NULL) 703 return (EINVAL); 704 if (sdp->sd_share != NULL) 705 return (EINVAL); 706 707 /* 708 * Is there already an IOD for this VC? 709 * (Should never happen.) 710 */ 711 SMB_VC_LOCK(vcp); 712 if (vcp->iod_thr == NULL) 713 vcp->iod_thr = curthread; 714 else 715 err = EEXIST; 716 SMB_VC_UNLOCK(vcp); 717 if (err) 718 return (err); 719 720 /* 721 * Copy the "work" state, etc. into the VC, 722 * and back to the caller on the way out. 723 * Clear the "out only" part. 724 */ 725 if (ddi_copyin((void *)arg, &vcp->vc_work, 726 sizeof (smbioc_ssn_work_t), flags)) { 727 err = EFAULT; 728 goto out; 729 } 730 vcp->vc_work.wk_out_state = 0; 731 732 switch (cmd) { 733 734 case SMBIOC_IOD_CONNECT: 735 err = nsmb_iod_connect(vcp); 736 break; 737 738 case SMBIOC_IOD_NEGOTIATE: 739 err = nsmb_iod_negotiate(vcp, cr); 740 break; 741 742 case SMBIOC_IOD_SSNSETUP: 743 err = nsmb_iod_ssnsetup(vcp, cr); 744 break; 745 746 case SMBIOC_IOD_WORK: 747 err = smb_iod_vc_work(vcp, flags, cr); 748 break; 749 750 case SMBIOC_IOD_IDLE: 751 err = smb_iod_vc_idle(vcp); 752 break; 753 754 case SMBIOC_IOD_RCFAIL: 755 err = smb_iod_vc_rcfail(vcp); 756 break; 757 758 default: 759 err = ENOTTY; 760 break; 761 } 762 763 out: 764 vcp->vc_work.wk_out_state = vcp->vc_state; 765 (void) ddi_copyout(&vcp->vc_work, (void *)arg, 766 sizeof (smbioc_ssn_work_t), flags); 767 768 /* 769 * The IOD thread is leaving the driver. Clear iod_thr, 770 * and wake up anybody waiting for us to quit. 771 */ 772 SMB_VC_LOCK(vcp); 773 vcp->iod_thr = NULL; 774 cv_broadcast(&vcp->vc_statechg); 775 SMB_VC_UNLOCK(vcp); 776 777 return (err); 778 } 779 780 int 781 smb_usr_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) 782 { 783 int err; 784 785 /* 786 * Serialize ioctl calls. The smb_usr_... functions 787 * don't expect concurrent calls on a given sdp. 788 */ 789 mutex_enter(&sdp->sd_lock); 790 if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) { 791 mutex_exit(&sdp->sd_lock); 792 return (EBUSY); 793 } 794 sdp->sd_flags |= NSMBFL_IOCTL; 795 mutex_exit(&sdp->sd_lock); 796 797 err = 0; 798 switch (cmd) { 799 case SMBIOC_GETVERS: 800 (void) ddi_copyout(&nsmb_version, (void *)arg, 801 sizeof (nsmb_version), flags); 802 break; 803 804 case SMBIOC_GETSSNKEY: 805 err = smb_usr_get_ssnkey(sdp, arg, flags); 806 break; 807 808 case SMBIOC_DUP_DEV: 809 err = smb_usr_dup_dev(sdp, arg, flags); 810 break; 811 812 case SMBIOC_XACTNP: 813 err = smb_usr_xnp(sdp, arg, flags, cr); 814 break; 815 816 case SMBIOC_READ: 817 case SMBIOC_WRITE: 818 err = smb_usr_rw(sdp, cmd, arg, flags, cr); 819 break; 820 821 case SMBIOC_NTCREATE: 822 err = smb_usr_ntcreate(sdp, arg, flags, cr); 823 break; 824 825 case SMBIOC_PRINTJOB: 826 err = smb_usr_printjob(sdp, arg, flags, cr); 827 break; 828 829 case SMBIOC_CLOSEFH: 830 err = smb_usr_closefh(sdp, cr); 831 break; 832 833 case SMBIOC_SSN_CREATE: 834 case SMBIOC_SSN_FIND: 835 err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr); 836 break; 837 838 case SMBIOC_SSN_KILL: 839 case SMBIOC_SSN_RELE: 840 err = smb_usr_drop_ssn(sdp, cmd); 841 break; 842 843 case SMBIOC_TREE_CONNECT: 844 case SMBIOC_TREE_FIND: 845 err = smb_usr_get_tree(sdp, cmd, arg, flags, cr); 846 break; 847 848 case SMBIOC_TREE_KILL: 849 case SMBIOC_TREE_RELE: 850 err = smb_usr_drop_tree(sdp, cmd); 851 break; 852 853 case SMBIOC_IOD_CONNECT: 854 case SMBIOC_IOD_NEGOTIATE: 855 case SMBIOC_IOD_SSNSETUP: 856 case SMBIOC_IOD_WORK: 857 case SMBIOC_IOD_IDLE: 858 case SMBIOC_IOD_RCFAIL: 859 err = smb_usr_iod_ioctl(sdp, cmd, arg, flags, cr); 860 break; 861 862 case SMBIOC_PK_ADD: 863 case SMBIOC_PK_DEL: 864 case SMBIOC_PK_CHK: 865 case SMBIOC_PK_DEL_OWNER: 866 case SMBIOC_PK_DEL_EVERYONE: 867 err = smb_pkey_ioctl(cmd, arg, flags, cr); 868 break; 869 870 default: 871 err = ENOTTY; 872 break; 873 } 874 875 mutex_enter(&sdp->sd_lock); 876 sdp->sd_flags &= ~NSMBFL_IOCTL; 877 mutex_exit(&sdp->sd_lock); 878 879 return (err); 880 } 881