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_conn.c,v 1.27.166.1 2005/05/27 02:35:29 lindak Exp $
33 */
34 /*
35 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
36 * Use is subject to license terms.
37 *
38 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
39 */
40
41 /*
42 * Connection engine.
43 */
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kmem.h>
48 #include <sys/proc.h>
49 #include <sys/lock.h>
50 #include <sys/vnode.h>
51 #include <sys/stream.h>
52 #include <sys/stropts.h>
53 #include <sys/socketvar.h>
54 #include <sys/cred.h>
55 #include <netinet/in.h>
56 #include <inet/ip.h>
57 #include <inet/ip6.h>
58 #include <sys/cmn_err.h>
59 #include <sys/thread.h>
60 #include <sys/atomic.h>
61 #include <sys/u8_textprep.h>
62
63 #include <netsmb/smb_osdep.h>
64
65 #include <netsmb/smb.h>
66 #include <netsmb/smb2.h>
67 #include <netsmb/smb_conn.h>
68 #include <netsmb/smb_subr.h>
69 #include <netsmb/smb_tran.h>
70 #include <netsmb/smb_pass.h>
71
72 static struct smb_connobj smb_vclist;
73
74 void smb_co_init(struct smb_connobj *cp, int level, char *objname);
75 void smb_co_done(struct smb_connobj *cp);
76 void smb_co_hold(struct smb_connobj *cp);
77 void smb_co_rele(struct smb_connobj *cp);
78 void smb_co_kill(struct smb_connobj *cp);
79
80 static void smb_vc_free(struct smb_connobj *cp);
81 static void smb_vc_gone(struct smb_connobj *cp);
82
83 static void smb_share_free(struct smb_connobj *cp);
84 static void smb_share_gone(struct smb_connobj *cp);
85
86 static void smb_fh_free(struct smb_connobj *cp);
87 static void smb_fh_gone(struct smb_connobj *cp);
88
89 int
smb_sm_init(void)90 smb_sm_init(void)
91 {
92 smb_co_init(&smb_vclist, SMBL_SM, "smbsm");
93 return (0);
94 }
95
96 int
smb_sm_idle(void)97 smb_sm_idle(void)
98 {
99 int error = 0;
100 SMB_CO_LOCK(&smb_vclist);
101 if (smb_vclist.co_usecount > 1) {
102 SMBSDEBUG("%d connections still active\n",
103 smb_vclist.co_usecount - 1);
104 error = EBUSY;
105 }
106 SMB_CO_UNLOCK(&smb_vclist);
107 return (error);
108 }
109
110 void
smb_sm_done(void)111 smb_sm_done(void)
112 {
113 /*
114 * Why are we not iterating on smb_vclist here?
115 * Because the caller has just called smb_sm_idle() to
116 * make sure we have no VCs before calling this.
117 */
118 smb_co_done(&smb_vclist);
119 }
120
121
122
123 /*
124 * Common code for connection object
125 */
126 /*ARGSUSED*/
127 void
smb_co_init(struct smb_connobj * cp,int level,char * objname)128 smb_co_init(struct smb_connobj *cp, int level, char *objname)
129 {
130
131 mutex_init(&cp->co_lock, objname, MUTEX_DRIVER, NULL);
132
133 cp->co_level = level;
134 cp->co_usecount = 1;
135 SLIST_INIT(&cp->co_children);
136 }
137
138 /*
139 * Called just before free of an object
140 * of which smb_connobj is a part, i.e.
141 * _vc_free, _share_free, also sm_done.
142 */
143 void
smb_co_done(struct smb_connobj * cp)144 smb_co_done(struct smb_connobj *cp)
145 {
146 ASSERT(SLIST_EMPTY(&cp->co_children));
147 mutex_destroy(&cp->co_lock);
148 }
149
150 static void
smb_co_addchild(struct smb_connobj * parent,struct smb_connobj * child)151 smb_co_addchild(
152 struct smb_connobj *parent,
153 struct smb_connobj *child)
154 {
155
156 /*
157 * Set the child's pointer to the parent.
158 * No references yet, so no need to lock.
159 */
160 ASSERT(child->co_usecount == 1);
161 child->co_parent = parent;
162
163 /*
164 * Add the child to the parent's list of
165 * children, and in-line smb_co_hold
166 */
167 ASSERT(MUTEX_HELD(&parent->co_lock));
168 parent->co_usecount++;
169 SLIST_INSERT_HEAD(&parent->co_children, child, co_next);
170 }
171
172 void
smb_co_hold(struct smb_connobj * cp)173 smb_co_hold(struct smb_connobj *cp)
174 {
175 SMB_CO_LOCK(cp);
176 cp->co_usecount++;
177 SMB_CO_UNLOCK(cp);
178 }
179
180 /*
181 * Called via smb_vc_rele, smb_share_rele
182 */
183 void
smb_co_rele(struct smb_connobj * co)184 smb_co_rele(struct smb_connobj *co)
185 {
186 struct smb_connobj *parent;
187 int old_flags;
188
189 SMB_CO_LOCK(co);
190
191 /*
192 * When VC usecount goes from 2 to 1, signal the iod_idle CV.
193 * It's unfortunate to have object type-specific logic here,
194 * but it's hard to do this anywhere else.
195 */
196 if (co->co_level == SMBL_VC && co->co_usecount == 2) {
197 smb_vc_t *vcp = CPTOVC(co);
198 cv_signal(&vcp->iod_idle);
199 }
200 if (co->co_usecount > 1) {
201 co->co_usecount--;
202 SMB_CO_UNLOCK(co);
203 return;
204 }
205 ASSERT(co->co_usecount == 1);
206 co->co_usecount = 0;
207
208 /*
209 * This list of children should be empty now.
210 * Check this while we're still linked, so
211 * we have a better chance of debugging.
212 */
213 ASSERT(SLIST_EMPTY(&co->co_children));
214
215 /*
216 * OK, this element is going away.
217 *
218 * We need to drop the lock on this CO so we can take the
219 * parent CO lock. The _GONE flag prevents this CO from
220 * getting new references before we can unlink it from the
221 * parent list.
222 *
223 * The _GONE flag is also used to ensure that the co_gone
224 * function is called only once. Note that smb_co_kill may
225 * do this before we get here. If we find that the _GONE
226 * flag was not already set, then call the co_gone hook
227 * (smb_share_gone, smb_vc_gone) which will disconnect
228 * the share or the VC, respectively.
229 *
230 * Note the old: smb_co_gone(co, scred);
231 * is now in-line here.
232 */
233 old_flags = co->co_flags;
234 co->co_flags |= SMBO_GONE;
235 SMB_CO_UNLOCK(co);
236
237 if ((old_flags & SMBO_GONE) == 0 && co->co_gone)
238 co->co_gone(co);
239
240 /*
241 * If we have a parent (only smb_vclist does not)
242 * then unlink from parent's list of children.
243 * We have the only reference to the child.
244 */
245 parent = co->co_parent;
246 if (parent) {
247 SMB_CO_LOCK(parent);
248 ASSERT(SLIST_FIRST(&parent->co_children));
249 if (SLIST_FIRST(&parent->co_children)) {
250 SLIST_REMOVE(&parent->co_children, co,
251 smb_connobj, co_next);
252 }
253 SMB_CO_UNLOCK(parent);
254 }
255
256 /*
257 * Now it's safe to free the CO
258 */
259 if (co->co_free) {
260 co->co_free(co);
261 }
262
263 /*
264 * Finally, if the CO had a parent, decrement
265 * the parent's hold count for the lost child.
266 */
267 if (parent) {
268 /*
269 * Recursive call here (easier for debugging).
270 * Can only go two levels.
271 */
272 smb_co_rele(parent);
273 }
274 }
275
276 /*
277 * Do just the first part of what co_gone does,
278 * i.e. tree disconnect, or disconnect a VC.
279 * This is used to forcibly close things.
280 */
281 void
smb_co_kill(struct smb_connobj * co)282 smb_co_kill(struct smb_connobj *co)
283 {
284 int old_flags;
285
286 SMB_CO_LOCK(co);
287 old_flags = co->co_flags;
288 co->co_flags |= SMBO_GONE;
289 SMB_CO_UNLOCK(co);
290
291 /*
292 * Do the same "call only once" logic here as in
293 * smb_co_rele, though it's probably not possible
294 * for this to be called after smb_co_rele.
295 */
296 if ((old_flags & SMBO_GONE) == 0 && co->co_gone)
297 co->co_gone(co);
298
299 /* XXX: Walk list of children and kill those too? */
300 }
301
302
303 /*
304 * Session objects, which are referred to as "VC" for
305 * "virtual cirtuit". This has nothing to do with the
306 * CIFS notion of a "virtual cirtuit". See smb_conn.h
307 */
308
309 void
smb_vc_hold(struct smb_vc * vcp)310 smb_vc_hold(struct smb_vc *vcp)
311 {
312 smb_co_hold(VCTOCP(vcp));
313 }
314
315 void
smb_vc_rele(struct smb_vc * vcp)316 smb_vc_rele(struct smb_vc *vcp)
317 {
318 smb_co_rele(VCTOCP(vcp));
319 }
320
321 void
smb_vc_kill(struct smb_vc * vcp)322 smb_vc_kill(struct smb_vc *vcp)
323 {
324 smb_co_kill(VCTOCP(vcp));
325 }
326
327 /*
328 * Normally called via smb_vc_rele()
329 * after co_usecount drops to zero.
330 * Also called via: smb_vc_kill()
331 *
332 * Shutdown the VC to this server,
333 * invalidate shares linked with it.
334 */
335 /*ARGSUSED*/
336 static void
smb_vc_gone(struct smb_connobj * cp)337 smb_vc_gone(struct smb_connobj *cp)
338 {
339 struct smb_vc *vcp = CPTOVC(cp);
340
341 /*
342 * Was smb_vc_disconnect(vcp);
343 */
344 smb_iod_disconnect(vcp);
345 }
346
347 /*
348 * The VC has no more references. Free it.
349 * No locks needed here.
350 */
351 static void
smb_vc_free(struct smb_connobj * cp)352 smb_vc_free(struct smb_connobj *cp)
353 {
354 struct smb_vc *vcp = CPTOVC(cp);
355
356 /*
357 * The _gone call should have emptied the request list,
358 * but let's make sure, as requests may have references
359 * to this VC without taking a hold. (The hold is the
360 * responsibility of threads placing requests.)
361 */
362 ASSERT(vcp->iod_rqlist.tqh_first == NULL);
363
364 if (vcp->vc_tdata)
365 SMB_TRAN_DONE(vcp);
366
367 /*
368 * We are not using the iconv routines here. So commenting them for now.
369 * REVISIT.
370 */
371 #ifdef NOTYETDEFINED
372 if (vcp->vc_tolower)
373 iconv_close(vcp->vc_tolower);
374 if (vcp->vc_toupper)
375 iconv_close(vcp->vc_toupper);
376 if (vcp->vc_tolocal)
377 iconv_close(vcp->vc_tolocal);
378 if (vcp->vc_toserver)
379 iconv_close(vcp->vc_toserver);
380 #endif
381
382 if (vcp->vc_mackey != NULL)
383 kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
384 if (vcp->vc_ssnkey != NULL)
385 kmem_free(vcp->vc_ssnkey, vcp->vc_ssnkeylen);
386
387 cv_destroy(&vcp->iod_muxwait);
388 cv_destroy(&vcp->iod_idle);
389 rw_destroy(&vcp->iod_rqlock);
390 cv_destroy(&vcp->vc_statechg);
391 smb_co_done(VCTOCP(vcp));
392 kmem_free(vcp, sizeof (*vcp));
393 }
394
395 /*ARGSUSED*/
396 int
smb_vc_create(smbioc_ossn_t * ossn,smb_cred_t * scred,smb_vc_t ** vcpp)397 smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
398 {
399 static char objtype[] = "smb_vc";
400 cred_t *cr = scred->scr_cred;
401 struct smb_vc *vcp;
402 int error = 0;
403
404 ASSERT(MUTEX_HELD(&smb_vclist.co_lock));
405
406 vcp = kmem_zalloc(sizeof (struct smb_vc), KM_SLEEP);
407
408 smb_co_init(VCTOCP(vcp), SMBL_VC, objtype);
409 vcp->vc_co.co_free = smb_vc_free;
410 vcp->vc_co.co_gone = smb_vc_gone;
411
412 cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
413 rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
414 cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL);
415 cv_init(&vcp->iod_muxwait, objtype, CV_DRIVER, NULL);
416
417 /* Expanded TAILQ_HEAD_INITIALIZER */
418 vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
419
420 /* A brand new VC should connect. */
421 vcp->vc_state = SMBIOD_ST_RECONNECT;
422
423 /*
424 * These identify the connection.
425 */
426 vcp->vc_zoneid = getzoneid();
427 bcopy(ossn, &vcp->vc_ssn, sizeof (*ossn));
428
429 /* This fills in vcp->vc_tdata */
430 vcp->vc_tdesc = &smb_tran_nbtcp_desc;
431 if ((error = SMB_TRAN_CREATE(vcp, cr)) != 0)
432 goto errout;
433
434 /* Success! */
435 smb_co_addchild(&smb_vclist, VCTOCP(vcp));
436 *vcpp = vcp;
437 return (0);
438
439 errout:
440 /*
441 * This will destroy the new vc.
442 * See: smb_vc_free
443 */
444 smb_vc_rele(vcp);
445 return (error);
446 }
447
448 /*
449 * Find or create a VC identified by the info in ossn
450 * and return it with a "hold", but not locked.
451 */
452 /*ARGSUSED*/
453 int
smb_vc_findcreate(smbioc_ossn_t * ossn,smb_cred_t * scred,smb_vc_t ** vcpp)454 smb_vc_findcreate(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
455 {
456 struct smb_connobj *co;
457 struct smb_vc *vcp;
458 smbioc_ssn_ident_t *vc_id;
459 int error;
460 zoneid_t zoneid = getzoneid();
461
462 *vcpp = vcp = NULL;
463
464 SMB_CO_LOCK(&smb_vclist);
465
466 /* var, head, next_field */
467 SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
468 vcp = CPTOVC(co);
469
470 /*
471 * Some things we can check without
472 * holding the lock (those that are
473 * set at creation and never change).
474 */
475
476 /* VCs in other zones are invisibile. */
477 if (vcp->vc_zoneid != zoneid)
478 continue;
479
480 /* Also segregate by Unix owner. */
481 if (vcp->vc_owner != ossn->ssn_owner)
482 continue;
483
484 /*
485 * Compare identifying info:
486 * server address, user, domain
487 * names are case-insensitive
488 */
489 vc_id = &vcp->vc_ssn.ssn_id;
490 if (bcmp(&vc_id->id_srvaddr,
491 &ossn->ssn_id.id_srvaddr,
492 sizeof (vc_id->id_srvaddr)))
493 continue;
494 if (u8_strcmp(vc_id->id_user, ossn->ssn_id.id_user, 0,
495 U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
496 continue;
497 if (u8_strcmp(vc_id->id_domain, ossn->ssn_id.id_domain, 0,
498 U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
499 continue;
500
501 /*
502 * We have a match, but still have to check
503 * the _GONE flag, and do that with a lock.
504 * No new references when _GONE is set.
505 *
506 * Also clear SMBVOPT_CREATE which the caller
507 * may check to find out if we did create.
508 */
509 SMB_VC_LOCK(vcp);
510 if ((vcp->vc_flags & SMBV_GONE) == 0) {
511 ossn->ssn_vopt &= ~SMBVOPT_CREATE;
512 /*
513 * Return it held, unlocked.
514 * In-line smb_vc_hold here.
515 */
516 co->co_usecount++;
517 SMB_VC_UNLOCK(vcp);
518 *vcpp = vcp;
519 error = 0;
520 goto out;
521 }
522 SMB_VC_UNLOCK(vcp);
523 /* keep looking. */
524 }
525 vcp = NULL;
526
527 /* Note: smb_vclist is still locked. */
528
529 if (ossn->ssn_vopt & SMBVOPT_CREATE) {
530 /*
531 * Create a new VC. It starts out with
532 * hold count = 1, so don't incr. here.
533 */
534 error = smb_vc_create(ossn, scred, &vcp);
535 if (error == 0)
536 *vcpp = vcp;
537 } else
538 error = ENOENT;
539
540 out:
541 SMB_CO_UNLOCK(&smb_vclist);
542 return (error);
543 }
544
545
546 /*
547 * Helper functions that operate on VCs
548 */
549
550 /*
551 * Get a pointer to the IP address suitable for passing to Trusted
552 * Extensions find_tpc() routine. Used by smbfs_mount_label_policy().
553 * Compare this code to nfs_mount_label_policy() if problems arise.
554 */
555 void *
smb_vc_getipaddr(struct smb_vc * vcp,int * ipvers)556 smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers)
557 {
558 smbioc_ssn_ident_t *id = &vcp->vc_ssn.ssn_id;
559 void *ret;
560
561 switch (id->id_srvaddr.sa.sa_family) {
562 case AF_INET:
563 *ipvers = IPV4_VERSION;
564 ret = &id->id_srvaddr.sin.sin_addr;
565 break;
566
567 case AF_INET6:
568 *ipvers = IPV6_VERSION;
569 ret = &id->id_srvaddr.sin6.sin6_addr;
570 break;
571 default:
572 SMBSDEBUG("invalid address family %d\n",
573 id->id_srvaddr.sa.sa_family);
574 *ipvers = 0;
575 ret = NULL;
576 break;
577 }
578 return (ret);
579 }
580
581 void
smb_vc_walkshares(struct smb_vc * vcp,walk_share_func_t func)582 smb_vc_walkshares(struct smb_vc *vcp,
583 walk_share_func_t func)
584 {
585 smb_connobj_t *co;
586 smb_share_t *ssp;
587
588 /*
589 * Walk the share list calling func(ssp, arg)
590 */
591 SMB_VC_LOCK(vcp);
592 SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
593 ssp = CPTOSS(co);
594 SMB_SS_LOCK(ssp);
595 func(ssp);
596 SMB_SS_UNLOCK(ssp);
597 }
598 SMB_VC_UNLOCK(vcp);
599 }
600
601
602 /*
603 * Share implementation
604 */
605
606 void
smb_share_hold(struct smb_share * ssp)607 smb_share_hold(struct smb_share *ssp)
608 {
609 smb_co_hold(SSTOCP(ssp));
610 }
611
612 void
smb_share_rele(struct smb_share * ssp)613 smb_share_rele(struct smb_share *ssp)
614 {
615 smb_co_rele(SSTOCP(ssp));
616 }
617
618 void
smb_share_kill(struct smb_share * ssp)619 smb_share_kill(struct smb_share *ssp)
620 {
621 smb_co_kill(SSTOCP(ssp));
622 }
623
624 /*
625 * Normally called via smb_share_rele()
626 * after co_usecount drops to zero.
627 * Also called via: smb_share_kill()
628 */
629 static void
smb_share_gone(struct smb_connobj * cp)630 smb_share_gone(struct smb_connobj *cp)
631 {
632 struct smb_cred scred;
633 struct smb_share *ssp = CPTOSS(cp);
634 smb_vc_t *vcp = SSTOVC(ssp);
635
636 smb_credinit(&scred, NULL);
637 smb_iod_shutdown_share(ssp);
638 if (vcp->vc_flags & SMBV_SMB2)
639 (void) smb2_smb_treedisconnect(ssp, &scred);
640 else
641 (void) smb_smb_treedisconnect(ssp, &scred);
642 smb_credrele(&scred);
643 }
644
645 /*
646 * Normally called via smb_share_rele()
647 * after co_usecount drops to zero.
648 */
649 static void
smb_share_free(struct smb_connobj * cp)650 smb_share_free(struct smb_connobj *cp)
651 {
652 struct smb_share *ssp = CPTOSS(cp);
653
654 cv_destroy(&ssp->ss_conn_done);
655 smb_co_done(SSTOCP(ssp));
656 kmem_free(ssp, sizeof (*ssp));
657 }
658
659 /*
660 * Allocate share structure and attach it to the given VC
661 * Connection expected to be locked on entry. Share will be returned
662 * in locked state.
663 */
664 /*ARGSUSED*/
665 int
smb_share_create(smbioc_tcon_t * tcon,struct smb_vc * vcp,struct smb_share ** sspp,struct smb_cred * scred)666 smb_share_create(smbioc_tcon_t *tcon, struct smb_vc *vcp,
667 struct smb_share **sspp, struct smb_cred *scred)
668 {
669 static char objtype[] = "smb_ss";
670 struct smb_share *ssp;
671
672 ASSERT(MUTEX_HELD(&vcp->vc_lock));
673
674 ssp = kmem_zalloc(sizeof (struct smb_share), KM_SLEEP);
675 smb_co_init(SSTOCP(ssp), SMBL_SHARE, objtype);
676 ssp->ss_co.co_free = smb_share_free;
677 ssp->ss_co.co_gone = smb_share_gone;
678
679 cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL);
680 ssp->ss_tid = SMB_TID_UNKNOWN;
681 ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
682
683 bcopy(&tcon->tc_sh, &ssp->ss_ioc,
684 sizeof (smbioc_oshare_t));
685
686 smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));
687 *sspp = ssp;
688
689 return (0);
690 }
691
692 /*
693 * Find or create a share under the given VC
694 * and return it with a "hold", but not locked.
695 */
696
697 int
smb_share_findcreate(smbioc_tcon_t * tcon,struct smb_vc * vcp,struct smb_share ** sspp,struct smb_cred * scred)698 smb_share_findcreate(smbioc_tcon_t *tcon, struct smb_vc *vcp,
699 struct smb_share **sspp, struct smb_cred *scred)
700 {
701 struct smb_connobj *co;
702 struct smb_share *ssp = NULL;
703 int error = 0;
704
705 *sspp = NULL;
706
707 SMB_VC_LOCK(vcp);
708
709 /* var, head, next_field */
710 SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
711 ssp = CPTOSS(co);
712
713 /* Share name */
714 if (u8_strcmp(ssp->ss_name, tcon->tc_sh.sh_name, 0,
715 U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
716 continue;
717
718 /*
719 * We have a match, but still have to check
720 * the _GONE flag, and do that with a lock.
721 * No new references when _GONE is set.
722 *
723 * Also clear SMBSOPT_CREATE which the caller
724 * may check to find out if we did create.
725 */
726 SMB_SS_LOCK(ssp);
727 if ((ssp->ss_flags & SMBS_GONE) == 0) {
728 tcon->tc_opt &= ~SMBSOPT_CREATE;
729 /*
730 * Return it held, unlocked.
731 * In-line smb_share_hold here.
732 */
733 co->co_usecount++;
734 SMB_SS_UNLOCK(ssp);
735 *sspp = ssp;
736 error = 0;
737 goto out;
738 }
739 SMB_SS_UNLOCK(ssp);
740 /* keep looking. */
741 }
742 ssp = NULL;
743
744 /* Note: vcp (list of shares) is still locked. */
745
746 if (tcon->tc_opt & SMBSOPT_CREATE) {
747 /*
748 * Create a new share. It starts out with
749 * hold count = 1, so don't incr. here.
750 */
751 error = smb_share_create(tcon, vcp, &ssp, scred);
752 if (error == 0)
753 *sspp = ssp;
754 } else
755 error = ENOENT;
756
757 out:
758 SMB_VC_UNLOCK(vcp);
759 return (error);
760 }
761
762
763 /*
764 * Helper functions that operate on shares
765 */
766
767 /*
768 * Mark this share as invalid, so consumers will know
769 * their file handles have become invalid.
770 *
771 * Most share consumers store a copy of ss_vcgenid when
772 * opening a file handle and compare that with what's in
773 * the share before using a file handle. If the genid
774 * doesn't match, the file handle has become "stale"
775 * due to disconnect. Therefore, zap ss_vcgenid here.
776 */
777 void
smb_share_invalidate(struct smb_share * ssp)778 smb_share_invalidate(struct smb_share *ssp)
779 {
780
781 ASSERT(MUTEX_HELD(&ssp->ss_lock));
782
783 ssp->ss_flags &= ~SMBS_CONNECTED;
784 ssp->ss_tid = SMB_TID_UNKNOWN;
785 ssp->ss_vcgenid = 0;
786 }
787
788 /*
789 * Connect (or reconnect) a share object.
790 *
791 * Called by smb_usr_get_tree() for new connections,
792 * and called by smb_rq_enqueue() for reconnect.
793 */
794 int
smb_share_tcon(smb_share_t * ssp,smb_cred_t * scred)795 smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
796 {
797 smb_vc_t *vcp = SSTOVC(ssp);
798 clock_t tmo;
799 int error;
800
801 SMB_SS_LOCK(ssp);
802
803 if (ssp->ss_flags & SMBS_CONNECTED) {
804 SMBIODEBUG("alread connected?");
805 error = 0;
806 goto out;
807 }
808
809 /*
810 * Wait for completion of any state changes
811 * that might be underway.
812 */
813 while (ssp->ss_flags & SMBS_RECONNECTING) {
814 ssp->ss_conn_waiters++;
815 tmo = cv_wait_sig(&ssp->ss_conn_done, &ssp->ss_lock);
816 ssp->ss_conn_waiters--;
817 if (tmo == 0) {
818 /* Interrupt! */
819 error = EINTR;
820 goto out;
821 }
822 }
823
824 /* Did someone else do it for us? */
825 if (ssp->ss_flags & SMBS_CONNECTED) {
826 error = 0;
827 goto out;
828 }
829
830 /*
831 * OK, we'll do the work.
832 */
833 ssp->ss_flags |= SMBS_RECONNECTING;
834
835 /*
836 * Drop the lock while doing the TCON.
837 * On success, sets ss_tid, ss_vcgenid,
838 * and ss_flags |= SMBS_CONNECTED;
839 */
840 SMB_SS_UNLOCK(ssp);
841 if (vcp->vc_flags & SMBV_SMB2)
842 error = smb2_smb_treeconnect(ssp, scred);
843 else
844 error = smb_smb_treeconnect(ssp, scred);
845 SMB_SS_LOCK(ssp);
846
847 ssp->ss_flags &= ~SMBS_RECONNECTING;
848
849 /* They can all go ahead! */
850 if (ssp->ss_conn_waiters)
851 cv_broadcast(&ssp->ss_conn_done);
852
853 out:
854 SMB_SS_UNLOCK(ssp);
855
856 return (error);
857 }
858
859 /*
860 * File handle level functions
861 */
862
863 void
smb_fh_hold(struct smb_fh * fhp)864 smb_fh_hold(struct smb_fh *fhp)
865 {
866 smb_co_hold(FHTOCP(fhp));
867 }
868
869 void
smb_fh_rele(struct smb_fh * fhp)870 smb_fh_rele(struct smb_fh *fhp)
871 {
872 smb_co_rele(FHTOCP(fhp));
873 }
874
875 void
smb_fh_close(struct smb_fh * fhp)876 smb_fh_close(struct smb_fh *fhp)
877 {
878 smb_co_kill(FHTOCP(fhp));
879 }
880
881 /*
882 * Normally called via smb_fh_rele()
883 * after co_usecount drops to zero.
884 * Also called via: smb_fh_kill()
885 */
886 static void
smb_fh_gone(struct smb_connobj * cp)887 smb_fh_gone(struct smb_connobj *cp)
888 {
889 struct smb_cred scred;
890 struct smb_fh *fhp = CPTOFH(cp);
891 smb_share_t *ssp = FHTOSS(fhp);
892 int err;
893
894 if ((fhp->fh_flags & SMBFH_VALID) == 0)
895 return;
896
897 /*
898 * We have no durable handles (yet) so if there has been a
899 * reconnect, don't bother to close this handle.
900 */
901 if (fhp->fh_vcgenid != ssp->ss_vcgenid)
902 return;
903
904 smb_credinit(&scred, NULL);
905 err = smb_smb_close(ssp, fhp, &scred);
906 smb_credrele(&scred);
907 if (err) {
908 SMBSDEBUG("close err=%d\n", err);
909 }
910 }
911
912 /*
913 * Normally called via smb_fh_rele()
914 * after co_usecount drops to zero.
915 */
916 static void
smb_fh_free(struct smb_connobj * cp)917 smb_fh_free(struct smb_connobj *cp)
918 {
919 struct smb_fh *fhp = CPTOFH(cp);
920
921 smb_co_done(FHTOCP(fhp));
922 kmem_free(fhp, sizeof (*fhp));
923 }
924
925 /*
926 * Allocate fh structure and attach it to the given share.
927 * Share expected to be locked on entry.
928 */
929 /*ARGSUSED*/
930 int
smb_fh_create(smb_share_t * ssp,struct smb_fh ** fhpp)931 smb_fh_create(smb_share_t *ssp, struct smb_fh **fhpp)
932 {
933 static char objtype[] = "smb_fh";
934 struct smb_fh *fhp;
935
936 fhp = kmem_zalloc(sizeof (struct smb_fh), KM_SLEEP);
937 smb_co_init(FHTOCP(fhp), SMBL_FH, objtype);
938 fhp->fh_co.co_free = smb_fh_free;
939 fhp->fh_co.co_gone = smb_fh_gone;
940
941 SMB_SS_LOCK(ssp);
942 if ((ssp->ss_flags & SMBS_GONE) != 0) {
943 SMB_SS_UNLOCK(ssp);
944 smb_fh_free(FHTOCP(fhp));
945 return (ENOTCONN);
946 }
947
948 smb_co_addchild(SSTOCP(ssp), FHTOCP(fhp));
949 *fhpp = fhp;
950 SMB_SS_UNLOCK(ssp);
951
952 return (0);
953 }
954
955 void
smb_fh_opened(struct smb_fh * fhp)956 smb_fh_opened(struct smb_fh *fhp)
957 {
958 smb_share_t *ssp = FHTOSS(fhp);
959
960 SMB_FH_LOCK(fhp);
961 fhp->fh_vcgenid = ssp->ss_vcgenid;
962 fhp->fh_flags |= SMBFH_VALID;
963 SMB_FH_UNLOCK(fhp);
964 }
965
966
967 /*
968 * Solaris zones support
969 */
970 /*ARGSUSED*/
971 void
lingering_vc(struct smb_vc * vc)972 lingering_vc(struct smb_vc *vc)
973 {
974 /* good place for a breakpoint */
975 DEBUG_ENTER("lingering VC");
976 }
977
978 /*
979 * On zone shutdown, kill any IOD threads still running in this zone.
980 */
981 /* ARGSUSED */
982 void
nsmb_zone_shutdown(zoneid_t zoneid,void * data)983 nsmb_zone_shutdown(zoneid_t zoneid, void *data)
984 {
985 struct smb_connobj *co;
986 struct smb_vc *vcp;
987
988 SMB_CO_LOCK(&smb_vclist);
989 SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
990 vcp = CPTOVC(co);
991
992 if (vcp->vc_zoneid != zoneid)
993 continue;
994
995 /*
996 * This will close the connection, and
997 * cause the IOD thread to terminate.
998 */
999 smb_vc_kill(vcp);
1000 }
1001 SMB_CO_UNLOCK(&smb_vclist);
1002 }
1003
1004 /*
1005 * On zone destroy, kill any IOD threads and free all resources they used.
1006 */
1007 /* ARGSUSED */
1008 void
nsmb_zone_destroy(zoneid_t zoneid,void * data)1009 nsmb_zone_destroy(zoneid_t zoneid, void *data)
1010 {
1011 struct smb_connobj *co;
1012 struct smb_vc *vcp;
1013
1014 /*
1015 * We will repeat what should have already happened
1016 * in zone_shutdown to make things go away.
1017 *
1018 * There should have been an smb_vc_rele call
1019 * by now for all VCs in the zone. If not,
1020 * there's probably more we needed to do in
1021 * the shutdown call.
1022 */
1023
1024 SMB_CO_LOCK(&smb_vclist);
1025
1026 if (smb_vclist.co_usecount > 1) {
1027 SMBERROR("%d connections still active\n",
1028 smb_vclist.co_usecount - 1);
1029 }
1030
1031 /* var, head, next_field */
1032 SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
1033 vcp = CPTOVC(co);
1034
1035 if (vcp->vc_zoneid != zoneid)
1036 continue;
1037
1038 /* Debugging */
1039 lingering_vc(vcp);
1040 }
1041
1042 SMB_CO_UNLOCK(&smb_vclist);
1043 }
1044