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