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