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