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_dev.c,v 1.21 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 40 #include <sys/types.h> 41 #include <sys/param.h> 42 #include <sys/errno.h> 43 #include <sys/sysmacros.h> 44 #include <sys/uio.h> 45 #include <sys/buf.h> 46 #include <sys/modctl.h> 47 #include <sys/open.h> 48 #include <sys/file.h> 49 #include <sys/kmem.h> 50 #include <sys/conf.h> 51 #include <sys/cmn_err.h> 52 #include <sys/stat.h> 53 #include <sys/ddi.h> 54 #include <sys/sunddi.h> 55 #include <sys/sunldi.h> 56 #include <sys/policy.h> 57 #include <sys/zone.h> 58 #include <sys/pathname.h> 59 #include <sys/mount.h> 60 #include <sys/sdt.h> 61 #include <fs/fs_subr.h> 62 #include <sys/modctl.h> 63 #include <sys/devops.h> 64 #include <sys/thread.h> 65 #include <sys/mkdev.h> 66 #include <sys/types.h> 67 #include <sys/zone.h> 68 69 #ifdef APPLE 70 #include <sys/smb_apple.h> 71 #else 72 #include <netsmb/smb_osdep.h> 73 #endif 74 75 #include <netsmb/mchain.h> /* for "htoles()" */ 76 77 #include <netsmb/smb.h> 78 #include <netsmb/smb_conn.h> 79 #include <netsmb/smb_subr.h> 80 #include <netsmb/smb_dev.h> 81 #include <netsmb/smb_pass.h> 82 83 /* for version checks */ 84 const uint32_t nsmb_version = NSMB_VERSION; 85 86 /* 87 * Userland code loops through minor #s 0 to 1023, looking for one which opens. 88 * Intially we create minor 0 and leave it for anyone. Minor zero will never 89 * actually get used - opening triggers creation of another (but private) minor, 90 * which userland code will get to and mark busy. 91 */ 92 #define SMBMINORS 1024 93 static void *statep; 94 static major_t nsmb_major; 95 static minor_t nsmb_minor = 1; 96 97 #define NSMB_MAX_MINOR (1 << 8) 98 #define NSMB_MIN_MINOR (NSMB_MAX_MINOR + 1) 99 100 #define ILP32 1 101 #define LP64 2 102 103 static kmutex_t dev_lck; 104 105 /* Zone support */ 106 zone_key_t nsmb_zone_key; 107 extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data); 108 extern void nsmb_zone_destroy(zoneid_t zoneid, void *data); 109 110 /* 111 * cb_ops device operations. 112 */ 113 static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp); 114 static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp); 115 static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 116 cred_t *credp, int *rvalp); 117 static int nsmb_close2(smb_dev_t *sdp, cred_t *cr); 118 119 /* smbfs cb_ops */ 120 static struct cb_ops nsmb_cbops = { 121 nsmb_open, /* open */ 122 nsmb_close, /* close */ 123 nodev, /* strategy */ 124 nodev, /* print */ 125 nodev, /* dump */ 126 nodev, /* read */ 127 nodev, /* write */ 128 nsmb_ioctl, /* ioctl */ 129 nodev, /* devmap */ 130 nodev, /* mmap */ 131 nodev, /* segmap */ 132 nochpoll, /* poll */ 133 ddi_prop_op, /* prop_op */ 134 NULL, /* stream */ 135 D_MP, /* cb_flag */ 136 CB_REV, /* rev */ 137 nodev, /* int (*cb_aread)() */ 138 nodev /* int (*cb_awrite)() */ 139 }; 140 141 /* 142 * Device options 143 */ 144 static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 145 static int nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 146 static int nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 147 void *arg, void **result); 148 149 static struct dev_ops nsmb_ops = { 150 DEVO_REV, /* devo_rev, */ 151 0, /* refcnt */ 152 nsmb_getinfo, /* info */ 153 nulldev, /* identify */ 154 nulldev, /* probe */ 155 nsmb_attach, /* attach */ 156 nsmb_detach, /* detach */ 157 nodev, /* reset */ 158 &nsmb_cbops, /* driver ops - devctl interfaces */ 159 NULL, /* bus operations */ 160 NULL, /* power */ 161 ddi_quiesce_not_needed, /* quiesce */ 162 }; 163 164 /* 165 * Module linkage information. 166 */ 167 168 static struct modldrv nsmb_modldrv = { 169 &mod_driverops, /* Driver module */ 170 "SMBFS network driver", 171 &nsmb_ops /* Driver ops */ 172 }; 173 174 static struct modlinkage nsmb_modlinkage = { 175 MODREV_1, 176 (void *)&nsmb_modldrv, 177 NULL 178 }; 179 180 int 181 _init(void) 182 { 183 int error; 184 185 ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1); 186 187 /* Can initialize some mutexes also. */ 188 mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL); 189 /* 190 * Create a major name and number. 191 */ 192 nsmb_major = ddi_name_to_major(NSMB_NAME); 193 nsmb_minor = 0; 194 195 /* Connection data structures. */ 196 (void) smb_sm_init(); 197 198 /* Initialize password Key chain DB. */ 199 smb_pkey_init(); 200 201 /* Initialize crypto mechanisms. */ 202 smb_crypto_mech_init(); 203 204 zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown, 205 nsmb_zone_destroy); 206 207 /* 208 * Install the module. Do this after other init, 209 * to prevent entrances before we're ready. 210 */ 211 if ((error = mod_install((&nsmb_modlinkage))) != 0) { 212 213 /* Same as 2nd half of _fini */ 214 (void) zone_key_delete(nsmb_zone_key); 215 smb_pkey_fini(); 216 smb_sm_done(); 217 mutex_destroy(&dev_lck); 218 ddi_soft_state_fini(&statep); 219 220 return (error); 221 } 222 223 return (0); 224 } 225 226 int 227 _fini(void) 228 { 229 int status; 230 231 /* 232 * Prevent unload if we have active VCs 233 * or stored passwords 234 */ 235 if ((status = smb_sm_idle()) != 0) 236 return (status); 237 if ((status = smb_pkey_idle()) != 0) 238 return (status); 239 240 /* 241 * Remove the module. Do this before destroying things, 242 * to prevent new entrances while we're destorying. 243 */ 244 if ((status = mod_remove(&nsmb_modlinkage)) != 0) { 245 return (status); 246 } 247 248 (void) zone_key_delete(nsmb_zone_key); 249 250 /* Destroy password Key chain DB. */ 251 smb_pkey_fini(); 252 253 smb_sm_done(); 254 255 mutex_destroy(&dev_lck); 256 ddi_soft_state_fini(&statep); 257 258 return (status); 259 } 260 261 int 262 _info(struct modinfo *modinfop) 263 { 264 return (mod_info(&nsmb_modlinkage, modinfop)); 265 } 266 267 /*ARGSUSED*/ 268 static int 269 nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 270 { 271 int ret = DDI_SUCCESS; 272 273 switch (cmd) { 274 case DDI_INFO_DEVT2DEVINFO: 275 *result = 0; 276 break; 277 case DDI_INFO_DEVT2INSTANCE: 278 *result = 0; 279 break; 280 default: 281 ret = DDI_FAILURE; 282 } 283 return (ret); 284 } 285 286 static int 287 nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 288 { 289 smb_dev_t *sdp; 290 291 if (cmd != DDI_ATTACH) 292 return (DDI_FAILURE); 293 /* 294 * only one instance - but we clone using the open routine 295 */ 296 if (ddi_get_instance(dip) > 0) 297 return (DDI_FAILURE); 298 299 mutex_enter(&dev_lck); 300 301 /* 302 * This is the Zero'th minor device which is created. 303 */ 304 if (ddi_soft_state_zalloc(statep, 0) == DDI_FAILURE) { 305 cmn_err(CE_WARN, "nsmb_attach: soft state alloc"); 306 goto attach_failed; 307 } 308 if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO, 309 NULL) == DDI_FAILURE) { 310 cmn_err(CE_WARN, "nsmb_attach: create minor"); 311 goto attach_failed; 312 } 313 if ((sdp = ddi_get_soft_state(statep, 0)) == NULL) { 314 cmn_err(CE_WARN, "nsmb_attach: get soft state"); 315 ddi_remove_minor_node(dip, NULL); 316 goto attach_failed; 317 } 318 319 /* 320 * Need to see if this field is required. 321 * REVISIT 322 */ 323 sdp->smb_dip = dip; 324 sdp->sd_seq = 0; 325 sdp->sd_opened = 1; 326 327 mutex_exit(&dev_lck); 328 ddi_report_dev(dip); 329 return (DDI_SUCCESS); 330 331 attach_failed: 332 ddi_soft_state_free(statep, 0); 333 mutex_exit(&dev_lck); 334 return (DDI_FAILURE); 335 } 336 337 /*ARGSUSED*/ 338 static int 339 nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 340 { 341 342 if (cmd != DDI_DETACH) 343 return (DDI_FAILURE); 344 if (ddi_get_instance(dip) > 0) 345 return (DDI_FAILURE); 346 347 ddi_soft_state_free(statep, 0); 348 ddi_remove_minor_node(dip, NULL); 349 350 return (DDI_SUCCESS); 351 } 352 353 /*ARGSUSED*/ 354 static int 355 nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */ 356 cred_t *cr, int *rvalp) 357 { 358 smb_dev_t *sdp; 359 int err; 360 361 sdp = ddi_get_soft_state(statep, getminor(dev)); 362 if (sdp == NULL) { 363 return (DDI_FAILURE); 364 } 365 if ((sdp->sd_flags & NSMBFL_OPEN) == 0) { 366 return (EBADF); 367 } 368 369 /* 370 * Dont give access if the zone id is not as the same as we 371 * set in the nsmb_open or dont belong to the global zone. 372 * Check if the user belongs to this zone.. 373 */ 374 if (sdp->zoneid != getzoneid()) 375 return (EIO); 376 377 /* 378 * We have a zone_shutdown call back that kills all the VCs 379 * in a zone that's shutting down. That action will cause 380 * all of these ioctls to fail on such VCs, so no need to 381 * check the zone status here on every ioctl call. 382 */ 383 384 err = 0; 385 switch (cmd) { 386 case SMBIOC_GETVERS: 387 ddi_copyout(&nsmb_version, (void *)arg, 388 sizeof (nsmb_version), flags); 389 break; 390 391 case SMBIOC_FLAGS2: 392 err = smb_usr_get_flags2(sdp, arg, flags); 393 break; 394 395 case SMBIOC_GETSSNKEY: 396 err = smb_usr_get_ssnkey(sdp, arg, flags); 397 break; 398 399 case SMBIOC_REQUEST: 400 err = smb_usr_simplerq(sdp, arg, flags, cr); 401 break; 402 403 case SMBIOC_T2RQ: 404 err = smb_usr_t2request(sdp, arg, flags, cr); 405 break; 406 407 case SMBIOC_READ: 408 case SMBIOC_WRITE: 409 err = smb_usr_rw(sdp, cmd, arg, flags, cr); 410 break; 411 412 case SMBIOC_SSN_CREATE: 413 case SMBIOC_SSN_FIND: 414 err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr); 415 break; 416 417 case SMBIOC_SSN_KILL: 418 case SMBIOC_SSN_RELE: 419 err = smb_usr_drop_ssn(sdp, cmd); 420 break; 421 422 case SMBIOC_TREE_CONNECT: 423 case SMBIOC_TREE_FIND: 424 err = smb_usr_get_tree(sdp, cmd, arg, flags, cr); 425 break; 426 427 case SMBIOC_TREE_KILL: 428 case SMBIOC_TREE_RELE: 429 err = smb_usr_drop_tree(sdp, cmd); 430 break; 431 432 case SMBIOC_IOD_WORK: 433 err = smb_usr_iod_work(sdp, arg, flags, cr); 434 break; 435 436 case SMBIOC_IOD_IDLE: 437 case SMBIOC_IOD_RCFAIL: 438 err = smb_usr_iod_ioctl(sdp, cmd, arg, flags); 439 break; 440 441 case SMBIOC_PK_ADD: 442 case SMBIOC_PK_DEL: 443 case SMBIOC_PK_CHK: 444 case SMBIOC_PK_DEL_OWNER: 445 case SMBIOC_PK_DEL_EVERYONE: 446 err = smb_pkey_ioctl(cmd, arg, flags, cr); 447 break; 448 449 default: 450 err = ENOTTY; 451 break; 452 } 453 454 return (err); 455 } 456 457 /*ARGSUSED*/ 458 static int 459 nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr) 460 { 461 major_t new_major; 462 smb_dev_t *sdp, *sdv; 463 464 mutex_enter(&dev_lck); 465 for (; ; ) { 466 minor_t start = nsmb_minor; 467 do { 468 if (nsmb_minor >= MAXMIN32) { 469 if (nsmb_major == getmajor(*dev)) 470 nsmb_minor = NSMB_MIN_MINOR; 471 else 472 nsmb_minor = 0; 473 } else { 474 nsmb_minor++; 475 } 476 sdv = ddi_get_soft_state(statep, nsmb_minor); 477 } while ((sdv != NULL) && (nsmb_minor != start)); 478 if (nsmb_minor == start) { 479 /* 480 * The condition we need to solve here is all the 481 * MAXMIN32(~262000) minors numbers are reached. We 482 * need to create a new major number. 483 * zfs uses getudev() to create a new major number. 484 */ 485 if ((new_major = getudev()) == (major_t)-1) { 486 cmn_err(CE_WARN, 487 "nsmb: Can't get unique major " 488 "device number."); 489 mutex_exit(&dev_lck); 490 return (-1); 491 } 492 nsmb_major = new_major; 493 nsmb_minor = 0; 494 } else { 495 break; 496 } 497 } 498 499 /* 500 * This is called by mount or open call. 501 * The open() routine is passed a pointer to a device number so 502 * that the driver can change the minor number. This allows 503 * drivers to dynamically create minor instances of the dev- 504 * ice. An example of this might be a pseudo-terminal driver 505 * that creates a new pseudo-terminal whenever it is opened. 506 * A driver that chooses the minor number dynamically, normally 507 * creates only one minor device node in attach(9E) with 508 * ddi_create_minor_node(9F) then changes the minor number com- 509 * ponent of *devp using makedevice(9F) and getmajor(9F) The 510 * driver needs to keep track of available minor numbers inter- 511 * nally. 512 * Stuff the structure smb_dev. 513 * return. 514 */ 515 516 if (ddi_soft_state_zalloc(statep, nsmb_minor) == DDI_FAILURE) { 517 mutex_exit(&dev_lck); 518 return (ENXIO); 519 } 520 if ((sdp = ddi_get_soft_state(statep, nsmb_minor)) == NULL) { 521 mutex_exit(&dev_lck); 522 return (ENXIO); 523 } 524 525 sdp->sd_opened = 1; 526 sdp->sd_seq = nsmb_minor; 527 sdp->smb_cred = cr; 528 sdp->sd_flags |= NSMBFL_OPEN; 529 sdp->zoneid = crgetzoneid(cr); 530 mutex_exit(&dev_lck); 531 532 *dev = makedevice(nsmb_major, nsmb_minor); 533 534 return (0); 535 } 536 537 /*ARGSUSED*/ 538 static int 539 nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr) 540 { 541 minor_t inst = getminor(dev); 542 smb_dev_t *sdp; 543 int err; 544 545 mutex_enter(&dev_lck); 546 /* 547 * 1. Check the validity of the minor number. 548 * 2. Release any shares/vc associated with the connection. 549 * 3. Can close the minor number. 550 * 4. Deallocate any resources allocated in open() call. 551 */ 552 553 sdp = ddi_get_soft_state(statep, inst); 554 if (sdp != NULL) 555 err = nsmb_close2(sdp, cr); 556 else 557 err = ENXIO; 558 559 /* 560 * Free the instance 561 */ 562 ddi_soft_state_free(statep, inst); 563 mutex_exit(&dev_lck); 564 return (err); 565 } 566 567 static int 568 nsmb_close2(smb_dev_t *sdp, cred_t *cr) 569 { 570 struct smb_vc *vcp; 571 struct smb_share *ssp; 572 struct smb_cred scred; 573 574 smb_credinit(&scred, cr); 575 ssp = sdp->sd_share; 576 if (ssp != NULL) 577 smb_share_rele(ssp); 578 vcp = sdp->sd_vc; 579 if (vcp != NULL) { 580 /* 581 * If this dev minor was opened by smbiod, 582 * mark this VC as "dead" because it now 583 * will have no IOD to service it. 584 */ 585 if (sdp->sd_flags & NSMBFL_IOD) 586 smb_iod_disconnect(vcp); 587 smb_vc_rele(vcp); 588 } 589 590 smb_credrele(&scred); 591 return (0); 592 } 593 594 int 595 smb_dev2share(int fd, struct smb_share **sspp) 596 { 597 file_t *fp = NULL; 598 vnode_t *vp; 599 smb_dev_t *sdp; 600 smb_share_t *ssp; 601 dev_t dev; 602 int err; 603 604 if ((fp = getf(fd)) == NULL) 605 return (EBADF); 606 607 vp = fp->f_vnode; 608 dev = vp->v_rdev; 609 if (dev == 0 || dev == NODEV || 610 getmajor(dev) != nsmb_major) { 611 err = EBADF; 612 goto out; 613 } 614 615 sdp = ddi_get_soft_state(statep, getminor(dev)); 616 if (sdp == NULL) { 617 err = EINVAL; 618 goto out; 619 } 620 621 ssp = sdp->sd_share; 622 if (ssp == NULL) { 623 err = ENOTCONN; 624 goto out; 625 } 626 627 /* 628 * Our caller gains a ref. to this share. 629 */ 630 *sspp = ssp; 631 smb_share_hold(ssp); 632 err = 0; 633 634 out: 635 if (fp) 636 releasef(fd); 637 return (err); 638 } 639