xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c (revision 456fcba7d95fa2a8c8a9131bbcccb8854cc2399a)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 /*
38  * Connection engine.
39  */
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kmem.h>
44 #include <sys/proc.h>
45 #include <sys/lock.h>
46 #include <sys/vnode.h>
47 #include <sys/stream.h>
48 #include <sys/stropts.h>
49 #include <sys/socketvar.h>
50 #include <sys/cred.h>
51 #include <sys/cred_impl.h>
52 #include <netinet/in.h>
53 #include <inet/ip.h>
54 #include <inet/ip6.h>
55 #include <sys/cmn_err.h>
56 #include <sys/thread.h>
57 #include <sys/atomic.h>
58 
59 #ifdef APPLE
60 #include <sys/smb_apple.h>
61 #include <sys/smb_iconv.h>
62 #else
63 #include <netsmb/smb_osdep.h>
64 #endif
65 
66 #include <netsmb/smb.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 static uint_t smb_vcnext = 0;	/* next unique id for VC */
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 #ifdef APPLE
82 static void smb_sm_lockvclist(void);
83 static void smb_sm_unlockvclist(void);
84 #endif
85 
86 static void smb_vc_free(struct smb_connobj *cp);
87 static void smb_vc_gone(struct smb_connobj *cp);
88 
89 static void smb_share_free(struct smb_connobj *cp);
90 static void smb_share_gone(struct smb_connobj *cp);
91 
92 /* smb_dup_sockaddr moved to smb_tran.c */
93 
94 int
95 smb_sm_init(void)
96 {
97 	smb_co_init(&smb_vclist, SMBL_SM, "smbsm");
98 	return (0);
99 }
100 
101 int
102 smb_sm_idle(void)
103 {
104 	int error = 0;
105 	SMB_CO_LOCK(&smb_vclist);
106 	if (smb_vclist.co_usecount > 1) {
107 		SMBSDEBUG("%d connections still active\n",
108 		    smb_vclist.co_usecount - 1);
109 		error = EBUSY;
110 	}
111 	SMB_CO_UNLOCK(&smb_vclist);
112 	return (error);
113 }
114 
115 void
116 smb_sm_done(void)
117 {
118 	/*
119 	 * XXX Q4BP why are we not iterating on smb_vclist here?
120 	 * Because the caller has just called smb_sm_idle() to
121 	 * make sure we have no VCs before calling this.
122 	 */
123 	smb_co_done(&smb_vclist);
124 }
125 
126 /*
127  * Find a VC identified by the info in vcspec,
128  * and return it with a "hold", but not locked.
129  */
130 /*ARGSUSED*/
131 static int
132 smb_sm_lookupvc(
133 	struct smb_vcspec *vcspec,
134 	struct smb_cred *scred,
135 	struct smb_vc **vcpp)
136 {
137 	struct smb_connobj *co;
138 	struct smb_vc *vcp;
139 	zoneid_t zoneid = getzoneid();
140 
141 	ASSERT(MUTEX_HELD(&smb_vclist.co_lock));
142 
143 	/* var, head, next_field */
144 	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
145 		vcp = CPTOVC(co);
146 
147 		/*
148 		 * Some things we can check without
149 		 * holding the lock (those that are
150 		 * set at creation and never change).
151 		 */
152 
153 		/* VCs in other zones are invisibile. */
154 		if (vcp->vc_zoneid != zoneid)
155 			continue;
156 
157 		/* Also segregate by owner. */
158 		if (vcp->vc_uid != vcspec->owner)
159 			continue;
160 
161 		/* XXX: we ignore the group.  Remove vc_gid? */
162 
163 		/* server */
164 		if (smb_cmp_sockaddr(vcp->vc_paddr, vcspec->sap))
165 			continue;
166 
167 		/* domain+user */
168 		if (strcmp(vcp->vc_domain, vcspec->domain))
169 			continue;
170 		if (strcmp(vcp->vc_username, vcspec->username))
171 			continue;
172 
173 		SMB_VC_LOCK(vcp);
174 
175 		/* No new references allowed when _GONE is set */
176 		if (vcp->vc_flags & SMBV_GONE)
177 			goto unlock_continue;
178 
179 		if (vcp->vc_vopt & SMBVOPT_PRIVATE)
180 			goto unlock_continue;
181 
182 	found:
183 		/*
184 		 * Success! (Found one we can use)
185 		 * Return with it held, unlocked.
186 		 * In-line smb_vc_hold here.
187 		 */
188 		co->co_usecount++;
189 		SMB_VC_UNLOCK(vcp);
190 		*vcpp = vcp;
191 		return (0);
192 
193 	unlock_continue:
194 		SMB_VC_UNLOCK(vcp);
195 		/* keep looking. */
196 	}
197 
198 	return (ENOENT);
199 }
200 
201 
202 int
203 smb_sm_negotiate(
204 	struct smb_vcspec *vcspec,
205 	struct smb_cred *scred,
206 	struct smb_vc **vcpp)
207 {
208 	struct smb_vc *vcp;
209 	clock_t tmo;
210 	int created, error;
211 
212 top:
213 	*vcpp = vcp = NULL;
214 
215 	SMB_CO_LOCK(&smb_vclist);
216 	error = smb_sm_lookupvc(vcspec, scred, &vcp);
217 	if (error) {
218 		/* The VC was not found.  Create? */
219 		if ((vcspec->optflags & SMBVOPT_CREATE) == 0) {
220 			SMB_CO_UNLOCK(&smb_vclist);
221 			return (error);
222 		}
223 		error = smb_vc_create(vcspec, scred, &vcp);
224 		if (error) {
225 			/* Could not create? Unusual. */
226 			SMB_CO_UNLOCK(&smb_vclist);
227 			return (error);
228 		}
229 		/* Note: co_usecount == 1 */
230 		created = 1;
231 	} else
232 		created = 0;
233 	SMB_CO_UNLOCK(&smb_vclist);
234 
235 	if (created) {
236 		/*
237 		 * We have a NEW VC, held, but not locked.
238 		 */
239 
240 		SMBIODEBUG("vc_state=%d\n", vcp->vc_state);
241 		switch (vcp->vc_state) {
242 
243 		case SMBIOD_ST_NOTCONN:
244 			(void) smb_vc_setup(vcspec, scred, vcp, 0);
245 			vcp->vc_genid++;
246 			/* XXX: Save credentials of caller here? */
247 			vcp->vc_state = SMBIOD_ST_RECONNECT;
248 			/* FALLTHROUGH */
249 
250 		case SMBIOD_ST_RECONNECT:
251 			error = smb_iod_connect(vcp);
252 			if (error)
253 				break;
254 			vcp->vc_state = SMBIOD_ST_TRANACTIVE;
255 			/* FALLTHROUGH */
256 
257 		case SMBIOD_ST_TRANACTIVE:
258 			/* XXX: Just pass vcspec instead? */
259 			vcp->vc_intok = vcspec->tok;
260 			vcp->vc_intoklen = vcspec->toklen;
261 			error = smb_smb_negotiate(vcp, &vcp->vc_scred);
262 			vcp->vc_intok = NULL;
263 			vcp->vc_intoklen = 0;
264 			if (error)
265 				break;
266 			vcp->vc_state = SMBIOD_ST_NEGOACTIVE;
267 			/* FALLTHROUGH */
268 
269 		case SMBIOD_ST_NEGOACTIVE:
270 		case SMBIOD_ST_SSNSETUP:
271 		case SMBIOD_ST_VCACTIVE:
272 			/* We can (re)use this VC. */
273 			error = 0;
274 			break;
275 
276 		default:
277 			error = EINVAL;
278 			break;
279 		}
280 
281 		SMB_VC_LOCK(vcp);
282 		cv_broadcast(&vcp->vc_statechg);
283 		SMB_VC_UNLOCK(vcp);
284 
285 	} else {
286 		/*
287 		 * Found an existing VC.  Reuse it, but first,
288 		 * wait for authentication to finish, etc.
289 		 * Note: We hold a reference on the VC.
290 		 */
291 		error = 0;
292 		SMB_VC_LOCK(vcp);
293 		while (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
294 			tmo = lbolt + SEC_TO_TICK(5);
295 			tmo = cv_timedwait_sig(&vcp->vc_statechg,
296 			    &vcp->vc_lock, tmo);
297 			if (tmo == 0) {
298 				error = EINTR;
299 				break;
300 			}
301 			if (vcp->vc_flags & SMBV_GONE)
302 				break;
303 		}
304 		SMB_VC_UNLOCK(vcp);
305 
306 		/* Interrupted? */
307 		if (error)
308 			goto out;
309 
310 		/*
311 		 * The other guy failed authentication,
312 		 * or otherwise gave up on this VC.
313 		 * Drop reference, start over.
314 		 */
315 		if (vcp->vc_flags & SMBV_GONE) {
316 			smb_vc_rele(vcp);
317 			goto top;
318 		}
319 
320 		ASSERT(vcp->vc_state == SMBIOD_ST_VCACTIVE);
321 		/* Success! */
322 	}
323 
324 out:
325 	if (error) {
326 		/*
327 		 * Undo the hold from lookupvc,
328 		 * or destroy if from vc_create.
329 		 */
330 		smb_vc_rele(vcp);
331 	} else {
332 		/* Return it held. */
333 		*vcpp = vcp;
334 	}
335 
336 	return (error);
337 }
338 
339 
340 int
341 smb_sm_ssnsetup(
342 	struct smb_vcspec *vcspec,
343 	struct smb_cred *scred,
344 	struct smb_vc *vcp)
345 {
346 	int error;
347 
348 	/*
349 	 * We have a VC, held, but not locked.
350 	 *
351 	 * Code from smb_iod_ssnsetup,
352 	 * with lots of rework.
353 	 */
354 
355 	SMBIODEBUG("vc_state=%d\n", vcp->vc_state);
356 	switch (vcp->vc_state) {
357 
358 	case SMBIOD_ST_NEGOACTIVE:
359 		/*
360 		 * This is the state we normally find.
361 		 * Calling _setup AGAIN to update the
362 		 * flags, security info, etc.
363 		 */
364 		error = smb_vc_setup(vcspec, scred, vcp, 1);
365 		if (error)
366 			break;
367 		vcp->vc_state = SMBIOD_ST_SSNSETUP;
368 		/* FALLTHROUGH */
369 
370 	case SMBIOD_ST_SSNSETUP:
371 		/* XXX: Just pass vcspec instead? */
372 		vcp->vc_intok = vcspec->tok;
373 		vcp->vc_intoklen = vcspec->toklen;
374 		error = smb_smb_ssnsetup(vcp, &vcp->vc_scred);
375 		vcp->vc_intok = NULL;
376 		vcp->vc_intoklen = 0;
377 		if (error)
378 			break;
379 		/* OK, start the reader thread... */
380 		error = smb_iod_create(vcp);
381 		if (error)
382 			break;
383 		vcp->vc_state = SMBIOD_ST_VCACTIVE;
384 		/* FALLTHROUGH */
385 
386 	case SMBIOD_ST_VCACTIVE:
387 		/* We can (re)use this VC. */
388 		error = 0;
389 		break;
390 
391 	default:
392 		error = EINVAL;
393 		break;
394 	}
395 
396 	SMB_VC_LOCK(vcp);
397 	cv_broadcast(&vcp->vc_statechg);
398 	SMB_VC_UNLOCK(vcp);
399 
400 	return (error);
401 }
402 
403 int
404 smb_sm_tcon(
405 	struct smb_sharespec *shspec,
406 	struct smb_cred *scred,
407 	struct smb_vc *vcp,
408 	struct smb_share **sspp)
409 {
410 	struct smb_share *ssp;
411 	int error;
412 
413 	*sspp = ssp = NULL;
414 
415 	if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
416 		/*
417 		 * The wait for vc_state in smb_sm_negotiate
418 		 * _should_ get us a VC in the right state.
419 		 */
420 		SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
421 		return (ENOTCONN);
422 	}
423 
424 	SMB_VC_LOCK(vcp);
425 	error = smb_vc_lookupshare(vcp, shspec, scred, &ssp);
426 	if (error) {
427 		/* The share was not found.  Create? */
428 		if ((shspec->optflags & SMBVOPT_CREATE) == 0) {
429 			SMB_VC_UNLOCK(vcp);
430 			return (error);
431 		}
432 		error = smb_share_create(vcp, shspec, scred, &ssp);
433 		if (error) {
434 			/* Could not create? Unusual. */
435 			SMB_VC_UNLOCK(vcp);
436 			return (error);
437 		}
438 		/* Note: co_usecount == 1 */
439 	}
440 	SMB_VC_UNLOCK(vcp);
441 
442 	/*
443 	 * We have a share, held, but not locked.
444 	 * Make it connected...
445 	 */
446 	SMB_SS_LOCK(ssp);
447 	if (!smb_share_valid(ssp))
448 		error = smb_share_tcon(ssp);
449 	SMB_SS_UNLOCK(ssp);
450 
451 	if (error) {
452 		/*
453 		 * Undo hold from lookupshare,
454 		 * or destroy if from _create.
455 		 */
456 		smb_share_rele(ssp);
457 	} else {
458 		/* Return it held. */
459 		*sspp = ssp;
460 	}
461 
462 	return (error);
463 }
464 
465 /*
466  * Common code for connection object
467  */
468 /*ARGSUSED*/
469 void
470 smb_co_init(struct smb_connobj *cp, int level, char *objname)
471 {
472 
473 	mutex_init(&cp->co_lock, objname,  MUTEX_DRIVER, NULL);
474 
475 	cp->co_level = level;
476 	cp->co_usecount = 1;
477 	SLIST_INIT(&cp->co_children);
478 }
479 
480 /*
481  * Called just before free of an object
482  * of which smb_connobj is a part, i.e.
483  * _vc_free, _share_free, also sm_done.
484  */
485 void
486 smb_co_done(struct smb_connobj *cp)
487 {
488 	ASSERT(SLIST_EMPTY(&cp->co_children));
489 	mutex_destroy(&cp->co_lock);
490 }
491 
492 static void
493 smb_co_addchild(
494 	struct smb_connobj *parent,
495 	struct smb_connobj *child)
496 {
497 
498 	/*
499 	 * Set the child's pointer to the parent.
500 	 * No references yet, so no need to lock.
501 	 */
502 	ASSERT(child->co_usecount == 1);
503 	child->co_parent = parent;
504 
505 	/*
506 	 * Add the child to the parent's list of
507 	 * children, and in-line smb_co_hold
508 	 */
509 	ASSERT(MUTEX_HELD(&parent->co_lock));
510 	parent->co_usecount++;
511 	SLIST_INSERT_HEAD(&parent->co_children, child, co_next);
512 }
513 
514 void
515 smb_co_hold(struct smb_connobj *cp)
516 {
517 	SMB_CO_LOCK(cp);
518 	cp->co_usecount++;
519 	SMB_CO_UNLOCK(cp);
520 }
521 
522 /*
523  * Called via smb_vc_rele, smb_share_rele
524  */
525 void
526 smb_co_rele(struct smb_connobj *co)
527 {
528 	struct smb_connobj *parent;
529 	int old_flags;
530 
531 	SMB_CO_LOCK(co);
532 	if (co->co_usecount > 1) {
533 		co->co_usecount--;
534 		SMB_CO_UNLOCK(co);
535 		return;
536 	}
537 	ASSERT(co->co_usecount == 1);
538 	co->co_usecount = 0;
539 
540 	/*
541 	 * This list of children should be empty now.
542 	 * Check this while we're still linked, so
543 	 * we have a better chance of debugging.
544 	 */
545 	ASSERT(SLIST_EMPTY(&co->co_children));
546 
547 	/*
548 	 * OK, this element is going away.
549 	 *
550 	 * We need to drop the lock on this CO so we can take the
551 	 * parent CO lock. The _GONE flag prevents this CO from
552 	 * getting new references before we can unlink it from the
553 	 * parent list.
554 	 *
555 	 * The _GONE flag is also used to ensure that the co_gone
556 	 * function is called only once.  Note that smb_co_kill may
557 	 * do this before we get here.  If we find that the _GONE
558 	 * flag was not already set, then call the co_gone hook
559 	 * (smb_share_gone, smb_vc_gone) which will disconnect
560 	 * the share or the VC, respectively.
561 	 *
562 	 * Note the old: smb_co_gone(co, scred);
563 	 * is now in-line here.
564 	 */
565 	old_flags = co->co_flags;
566 	co->co_flags |= SMBO_GONE;
567 	SMB_CO_UNLOCK(co);
568 
569 	if ((old_flags & SMBO_GONE) == 0 && co->co_gone)
570 		co->co_gone(co);
571 
572 	/*
573 	 * If we have a parent (only smb_vclist does not)
574 	 * then unlink from parent's list of children.
575 	 * We have the only reference to the child.
576 	 */
577 	parent = co->co_parent;
578 	if (parent) {
579 		SMB_CO_LOCK(parent);
580 		ASSERT(SLIST_FIRST(&parent->co_children));
581 		if (SLIST_FIRST(&parent->co_children)) {
582 			SLIST_REMOVE(&parent->co_children, co,
583 			    smb_connobj, co_next);
584 		}
585 		SMB_CO_UNLOCK(parent);
586 	}
587 
588 	/*
589 	 * Now it's safe to free the CO
590 	 */
591 	if (co->co_free) {
592 		co->co_free(co);
593 	}
594 
595 	/*
596 	 * Finally, if the CO had a parent, decrement
597 	 * the parent's hold count for the lost child.
598 	 */
599 	if (parent) {
600 		/*
601 		 * Recursive call here (easier for debugging).
602 		 * Can only go two levels.
603 		 */
604 		smb_co_rele(parent);
605 	}
606 }
607 
608 /*
609  * Do just the first part of what co_gone does,
610  * i.e. tree disconnect, or disconnect a VC.
611  * This is used to forcibly close things.
612  */
613 void
614 smb_co_kill(struct smb_connobj *co)
615 {
616 	int old_flags;
617 
618 	SMB_CO_LOCK(co);
619 	old_flags = co->co_flags;
620 	co->co_flags |= SMBO_GONE;
621 	SMB_CO_UNLOCK(co);
622 
623 	/*
624 	 * Do the same "call only once" logic here as in
625 	 * smb_co_rele, though it's probably not possible
626 	 * for this to be called after smb_co_rele.
627 	 */
628 	if ((old_flags & SMBO_GONE) == 0 && co->co_gone)
629 		co->co_gone(co);
630 
631 	/* XXX: Walk list of children and kill those too? */
632 }
633 
634 
635 /*
636  * Session implementation
637  */
638 
639 /*
640  * This sets the fields that are allowed to change
641  * when doing a reconnect.  Many others are set in
642  * smb_vc_create and never change afterwards.
643  * Don't want domain or user to change here.
644  */
645 int
646 smb_vc_setup(struct smb_vcspec *vcspec, struct smb_cred *scred,
647 	struct smb_vc *vcp, int is_ss)
648 {
649 	int error, minauth;
650 
651 	/* Just save all the SMBVOPT_ options. */
652 	vcp->vc_vopt = vcspec->optflags;
653 
654 	/* Cleared if nego response shows antique server! */
655 	vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
656 
657 	/* XXX: Odd place for this. */
658 	if (vcspec->optflags & SMBVOPT_EXT_SEC)
659 		vcp->vc_hflags2 |= SMB_FLAGS2_EXT_SEC;
660 
661 	if (is_ss) {
662 		/* Called from smb_sm_ssnsetup */
663 
664 		if (vcspec->optflags & SMBVOPT_USE_KEYCHAIN) {
665 			/*
666 			 * Get p/w hashes from the keychain.
667 			 * The password in vcspec->pass is
668 			 * fiction, so don't store it.
669 			 */
670 			error = smb_pkey_getpwh(vcp, scred->vc_ucred);
671 			return (error);
672 		}
673 
674 		/*
675 		 * Note: this can be called more than once
676 		 * for a given vcp, so free the old strings.
677 		 */
678 		SMB_STRFREE(vcp->vc_pass);
679 
680 		/*
681 		 * Don't store the cleartext password
682 		 * unless the minauth value was changed
683 		 * to allow use of cleartext passwords.
684 		 * (By default, this is not allowed.)
685 		 */
686 		minauth = vcspec->optflags & SMBVOPT_MINAUTH;
687 		if (minauth == SMBVOPT_MINAUTH_NONE)
688 			vcp->vc_pass = smb_strdup(vcspec->pass);
689 
690 		/* Compute LM and NTLM hashes. */
691 		smb_oldlm_hash(vcspec->pass, vcp->vc_lmhash);
692 		smb_ntlmv1hash(vcspec->pass, vcp->vc_nthash);
693 	}
694 
695 	/* Success! */
696 	error = 0;
697 	return (error);
698 }
699 
700 /*ARGSUSED*/
701 int
702 smb_vc_create(struct smb_vcspec *vcspec,
703 	struct smb_cred *scred, struct smb_vc **vcpp)
704 {
705 	static char objtype[] = "smb_vc";
706 	struct smb_vc *vcp;
707 	int error = 0;
708 
709 	ASSERT(MUTEX_HELD(&smb_vclist.co_lock));
710 
711 	/*
712 	 * Checks for valid uid/gid are now in
713 	 * smb_usr_ioc2vcspec, so at this point
714 	 * we know the user has right to create
715 	 * with the uid/gid in the vcspec.
716 	 */
717 
718 	vcp = kmem_zalloc(sizeof (struct smb_vc), KM_SLEEP);
719 
720 	smb_co_init(VCTOCP(vcp), SMBL_VC, objtype);
721 	vcp->vc_co.co_free = smb_vc_free;
722 	vcp->vc_co.co_gone = smb_vc_gone;
723 
724 	cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
725 	sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL);
726 	rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
727 	cv_init(&vcp->iod_exit, objtype, CV_DRIVER, NULL);
728 
729 	vcp->vc_number = atomic_inc_uint_nv(&smb_vcnext);
730 	vcp->vc_state = SMBIOD_ST_NOTCONN;
731 	vcp->vc_timo = SMB_DEFRQTIMO;
732 	/*
733 	 * I think SMB_UID_UNKNOWN is not the correct
734 	 * initial value for vc_smbuid. See the long
735 	 * comment in smb_iod_sendrq()
736 	 */
737 	vcp->vc_smbuid = SMB_UID_UNKNOWN; /* XXX should be zero */
738 	vcp->vc_tdesc = &smb_tran_nbtcp_desc;
739 
740 	/*
741 	 * These identify the connection.
742 	 */
743 	vcp->vc_zoneid = getzoneid();
744 	vcp->vc_uid = vcspec->owner;
745 	vcp->vc_grp = vcspec->group;
746 	vcp->vc_mode = vcspec->rights & SMBM_MASK;
747 
748 	vcp->vc_domain = smb_strdup(vcspec->domain);
749 	vcp->vc_username = smb_strdup(vcspec->username);
750 	vcp->vc_srvname = smb_strdup(vcspec->srvname);
751 	vcp->vc_paddr = smb_dup_sockaddr(vcspec->sap);
752 	vcp->vc_laddr = smb_dup_sockaddr(vcspec->lap);
753 
754 #ifdef NOICONVSUPPORT
755 	/*
756 	 * REVISIT
757 	 */
758 	error = iconv_open("tolower", vcspec->localcs, &vcp->vc_tolower);
759 	if (error)
760 		goto errout;
761 
762 	error = iconv_open("toupper", vcspec->localcs, &vcp->vc_toupper);
763 	if (error)
764 		goto errout;
765 
766 	if (vcspec->servercs[0]) {
767 
768 		error = iconv_open(vcspec->servercs, vcspec->localcs,
769 		    &vcp->vc_toserver);
770 		if (error)
771 			goto errout;
772 
773 		error = iconv_open(vcspec->localcs, vcspec->servercs,
774 		    &vcp->vc_tolocal);
775 		if (error)
776 			goto errout;
777 	}
778 #endif /* NOICONVSUPPORT */
779 
780 	/* This fills in vcp->vc_tdata */
781 	if ((error = SMB_TRAN_CREATE(vcp, curproc)) != 0)
782 		goto errout;
783 
784 	/* Success! */
785 	smb_co_addchild(&smb_vclist, VCTOCP(vcp));
786 	*vcpp = vcp;
787 	return (0);
788 
789 errout:
790 	/*
791 	 * This will destroy the new vc.
792 	 * See: smb_vc_free
793 	 */
794 	smb_vc_rele(vcp);
795 	return (error);
796 }
797 
798 void
799 smb_vc_hold(struct smb_vc *vcp)
800 {
801 	smb_co_hold(VCTOCP(vcp));
802 }
803 
804 void
805 smb_vc_rele(struct smb_vc *vcp)
806 {
807 	smb_co_rele(VCTOCP(vcp));
808 }
809 
810 void
811 smb_vc_kill(struct smb_vc *vcp)
812 {
813 	smb_co_kill(VCTOCP(vcp));
814 }
815 
816 /*
817  * Normally called via smb_vc_rele()
818  * after co_usecount drops to zero.
819  * Also called via: smb_vc_kill()
820  *
821  * Shutdown the VC to this server,
822  * invalidate shares linked with it.
823  */
824 /*ARGSUSED*/
825 static void
826 smb_vc_gone(struct smb_connobj *cp)
827 {
828 	struct smb_vc *vcp = CPTOVC(cp);
829 
830 	/*
831 	 * Was smb_vc_disconnect(vcp);
832 	 */
833 	smb_iod_disconnect(vcp);
834 
835 	/* Note: smb_iod_destroy in vc_free */
836 }
837 
838 static void
839 smb_vc_free(struct smb_connobj *cp)
840 {
841 	struct smb_vc *vcp = CPTOVC(cp);
842 
843 	/*
844 	 * The VC has no more references, so
845 	 * no locks should be needed here.
846 	 * Make sure the IOD is gone.
847 	 */
848 	smb_iod_destroy(vcp);
849 
850 	if (vcp->vc_tdata)
851 		SMB_TRAN_DONE(vcp, curproc);
852 
853 	SMB_STRFREE(vcp->vc_username);
854 	SMB_STRFREE(vcp->vc_srvname);
855 	SMB_STRFREE(vcp->vc_pass);
856 	SMB_STRFREE(vcp->vc_domain);
857 	if (vcp->vc_paddr) {
858 		smb_free_sockaddr(vcp->vc_paddr);
859 		vcp->vc_paddr = NULL;
860 	}
861 	if (vcp->vc_laddr) {
862 		smb_free_sockaddr(vcp->vc_laddr);
863 		vcp->vc_laddr = NULL;
864 	}
865 
866 /*
867  * We are not using the iconv routines here. So commenting them for now.
868  * REVISIT.
869  */
870 #ifdef NOTYETDEFINED
871 	if (vcp->vc_tolower)
872 		iconv_close(vcp->vc_tolower);
873 	if (vcp->vc_toupper)
874 		iconv_close(vcp->vc_toupper);
875 	if (vcp->vc_tolocal)
876 		iconv_close(vcp->vc_tolocal);
877 	if (vcp->vc_toserver)
878 		iconv_close(vcp->vc_toserver);
879 #endif
880 	if (vcp->vc_intok)
881 		kmem_free(vcp->vc_intok, vcp->vc_intoklen);
882 	if (vcp->vc_outtok)
883 		kmem_free(vcp->vc_outtok, vcp->vc_outtoklen);
884 	if (vcp->vc_negtok)
885 		kmem_free(vcp->vc_negtok, vcp->vc_negtoklen);
886 
887 	cv_destroy(&vcp->iod_exit);
888 	rw_destroy(&vcp->iod_rqlock);
889 	sema_destroy(&vcp->vc_sendlock);
890 	cv_destroy(&vcp->vc_statechg);
891 	smb_co_done(VCTOCP(vcp));
892 	kmem_free(vcp, sizeof (*vcp));
893 }
894 
895 
896 /*
897  * Lookup share in the given VC. Share referenced and locked on return.
898  * VC expected to be locked on entry and will be left locked on exit.
899  */
900 /*ARGSUSED*/
901 int
902 smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *shspec,
903 	struct smb_cred *scred,	struct smb_share **sspp)
904 {
905 	struct smb_connobj *co;
906 	struct smb_share *ssp = NULL;
907 
908 	ASSERT(MUTEX_HELD(&vcp->vc_lock));
909 
910 	*sspp = NULL;
911 
912 	/* var, head, next_field */
913 	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
914 		ssp = CPTOSS(co);
915 
916 		/* No new refs if _GONE is set. */
917 		if (ssp->ss_flags & SMBS_GONE)
918 			continue;
919 
920 		/* This has a hold, so no need to lock it. */
921 		if (strcmp(ssp->ss_name, shspec->name) == 0)
922 			goto found;
923 	}
924 	return (ENOENT);
925 
926 found:
927 	/* Return it with a hold. */
928 	smb_share_hold(ssp);
929 	*sspp = ssp;
930 	return (0);
931 }
932 
933 
934 static char smb_emptypass[] = "";
935 
936 const char *
937 smb_vc_getpass(struct smb_vc *vcp)
938 {
939 	if (vcp->vc_pass)
940 		return (vcp->vc_pass);
941 	return (smb_emptypass);
942 }
943 
944 uint16_t
945 smb_vc_nextmid(struct smb_vc *vcp)
946 {
947 	uint16_t r;
948 
949 	r = atomic_inc_16_nv(&vcp->vc_mid);
950 	return (r);
951 }
952 
953 /*
954  * Get a pointer to the IP address suitable for passing to Trusted
955  * Extensions find_tpc() routine.  Used by smbfs_mount_label_policy().
956  * Compare this code to nfs_mount_label_policy() if problems arise.
957  * Without support for direct CIFS-over-TCP, we should always see
958  * an AF_NETBIOS sockaddr here.
959  */
960 void *
961 smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers)
962 {
963 	switch (vcp->vc_paddr->sa_family) {
964 	case AF_NETBIOS: {
965 		struct sockaddr_nb *snb;
966 
967 		*ipvers = IPV4_VERSION;
968 		/*LINTED*/
969 		snb = (struct sockaddr_nb *)vcp->vc_paddr;
970 		return ((void *)&snb->snb_ipaddr);
971 	}
972 	case AF_INET: {
973 		struct sockaddr_in *sin;
974 
975 		*ipvers = IPV4_VERSION;
976 		/*LINTED*/
977 		sin = (struct sockaddr_in *)vcp->vc_paddr;
978 		return ((void *)&sin->sin_addr);
979 	}
980 	case AF_INET6: {
981 		struct sockaddr_in6 *sin6;
982 
983 		*ipvers = IPV6_VERSION;
984 		/*LINTED*/
985 		sin6 = (struct sockaddr_in6 *)vcp->vc_paddr;
986 		return ((void *)&sin6->sin6_addr);
987 	}
988 	default:
989 		SMBSDEBUG("invalid address family %d\n",
990 		    vcp->vc_paddr->sa_family);
991 		*ipvers = 0;
992 		return (NULL);
993 	}
994 }
995 
996 /*
997  * Share implementation
998  */
999 /*
1000  * Allocate share structure and attach it to the given VC
1001  * Connection expected to be locked on entry. Share will be returned
1002  * in locked state.
1003  */
1004 /*ARGSUSED*/
1005 int
1006 smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec,
1007 	struct smb_cred *scred, struct smb_share **sspp)
1008 {
1009 	static char objtype[] = "smb_ss";
1010 	struct smb_share *ssp;
1011 
1012 	ASSERT(MUTEX_HELD(&vcp->vc_lock));
1013 
1014 	ssp = kmem_zalloc(sizeof (struct smb_share), KM_SLEEP);
1015 	smb_co_init(SSTOCP(ssp), SMBL_SHARE, objtype);
1016 	ssp->ss_co.co_free = smb_share_free;
1017 	ssp->ss_co.co_gone = smb_share_gone;
1018 
1019 	ssp->ss_name = smb_strdup(shspec->name);
1020 	ssp->ss_mount = NULL;
1021 	if (shspec->pass && shspec->pass[0])
1022 		ssp->ss_pass = smb_strdup(shspec->pass);
1023 	ssp->ss_type = shspec->stype;
1024 	ssp->ss_tid = SMB_TID_UNKNOWN;
1025 	ssp->ss_mode = shspec->rights & SMBM_MASK;
1026 	ssp->ss_fsname = NULL;
1027 	smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));
1028 	*sspp = ssp;
1029 
1030 	return (0);
1031 }
1032 
1033 /*
1034  * Normally called via smb_share_rele()
1035  * after co_usecount drops to zero.
1036  */
1037 static void
1038 smb_share_free(struct smb_connobj *cp)
1039 {
1040 	struct smb_share *ssp = CPTOSS(cp);
1041 
1042 	SMB_STRFREE(ssp->ss_name);
1043 	SMB_STRFREE(ssp->ss_pass);
1044 	SMB_STRFREE(ssp->ss_fsname);
1045 	smb_co_done(SSTOCP(ssp));
1046 	kmem_free(ssp, sizeof (*ssp));
1047 }
1048 
1049 /*
1050  * Normally called via smb_share_rele()
1051  * after co_usecount drops to zero.
1052  * Also called via: smb_share_kill()
1053  */
1054 static void
1055 smb_share_gone(struct smb_connobj *cp)
1056 {
1057 	struct smb_cred scred;
1058 	struct smb_share *ssp = CPTOSS(cp);
1059 
1060 	smb_credinit(&scred, curproc, NULL);
1061 	smb_iod_shutdown_share(ssp);
1062 	smb_smb_treedisconnect(ssp, &scred);
1063 	smb_credrele(&scred);
1064 }
1065 
1066 void
1067 smb_share_hold(struct smb_share *ssp)
1068 {
1069 	smb_co_hold(SSTOCP(ssp));
1070 }
1071 
1072 void
1073 smb_share_rele(struct smb_share *ssp)
1074 {
1075 	smb_co_rele(SSTOCP(ssp));
1076 }
1077 
1078 void
1079 smb_share_kill(struct smb_share *ssp)
1080 {
1081 	smb_co_kill(SSTOCP(ssp));
1082 }
1083 
1084 
1085 void
1086 smb_share_invalidate(struct smb_share *ssp)
1087 {
1088 	ssp->ss_tid = SMB_TID_UNKNOWN;
1089 }
1090 
1091 /*
1092  * Returns NON-zero if the share is valid.
1093  * Called with the share locked.
1094  */
1095 int
1096 smb_share_valid(struct smb_share *ssp)
1097 {
1098 	struct smb_vc *vcp = SSTOVC(ssp);
1099 
1100 	ASSERT(MUTEX_HELD(&ssp->ss_lock));
1101 
1102 	if ((ssp->ss_flags & SMBS_CONNECTED) == 0)
1103 		return (0);
1104 
1105 	if (ssp->ss_tid == SMB_TID_UNKNOWN) {
1106 		SMBIODEBUG("found TID unknown\n");
1107 		ssp->ss_flags &= ~SMBS_CONNECTED;
1108 	}
1109 
1110 	if (ssp->ss_vcgenid != vcp->vc_genid) {
1111 		SMBIODEBUG("wrong genid\n");
1112 		ssp->ss_flags &= ~SMBS_CONNECTED;
1113 	}
1114 
1115 	return (ssp->ss_flags & SMBS_CONNECTED);
1116 }
1117 
1118 /*
1119  * Connect (or reconnect) a share object.
1120  * Called with the share locked.
1121  */
1122 int
1123 smb_share_tcon(struct smb_share *ssp)
1124 {
1125 	struct smb_vc *vcp = SSTOVC(ssp);
1126 	clock_t tmo;
1127 	int error;
1128 
1129 	ASSERT(MUTEX_HELD(&ssp->ss_lock));
1130 
1131 	if (ssp->ss_flags & SMBS_CONNECTED) {
1132 		SMBIODEBUG("alread connected?");
1133 		return (0);
1134 	}
1135 
1136 	/*
1137 	 * Wait for completion of any state changes
1138 	 * that might be underway.
1139 	 */
1140 	while (ssp->ss_flags & SMBS_RECONNECTING) {
1141 		ssp->ss_conn_waiters++;
1142 		tmo = cv_wait_sig(&ssp->ss_conn_done, &ssp->ss_lock);
1143 		ssp->ss_conn_waiters--;
1144 		if (tmo == 0) {
1145 			/* Interrupt! */
1146 			return (EINTR);
1147 		}
1148 	}
1149 
1150 	/* Did someone else do it for us? */
1151 	if (ssp->ss_flags & SMBS_CONNECTED)
1152 		return (0);
1153 
1154 	/*
1155 	 * OK, we'll do the work.
1156 	 */
1157 	ssp->ss_flags |= SMBS_RECONNECTING;
1158 
1159 	/* Drop the lock while doing the call. */
1160 	SMB_SS_UNLOCK(ssp);
1161 	error = smb_smb_treeconnect(ssp, &vcp->vc_scred);
1162 	SMB_SS_LOCK(ssp);
1163 
1164 	if (!error)
1165 		ssp->ss_flags |= SMBS_CONNECTED;
1166 	ssp->ss_flags &= ~SMBS_RECONNECTING;
1167 
1168 	/* They can all go ahead! */
1169 	if (ssp->ss_conn_waiters)
1170 		cv_broadcast(&ssp->ss_conn_done);
1171 
1172 	return (error);
1173 }
1174 
1175 const char *
1176 smb_share_getpass(struct smb_share *ssp)
1177 {
1178 	struct smb_vc *vcp;
1179 
1180 	if (ssp->ss_pass)
1181 		return (ssp->ss_pass);
1182 	vcp = SSTOVC(ssp);
1183 	if (vcp->vc_pass)
1184 		return (vcp->vc_pass);
1185 	return (smb_emptypass);
1186 }
1187 
1188 int
1189 smb_share_count(void)
1190 {
1191 	struct smb_connobj *covc, *coss;
1192 	struct smb_vc *vcp;
1193 	zoneid_t zoneid = getzoneid();
1194 	int nshares = 0;
1195 
1196 	SMB_CO_LOCK(&smb_vclist);
1197 	SLIST_FOREACH(covc, &smb_vclist.co_children, co_next) {
1198 		vcp = CPTOVC(covc);
1199 
1200 		/* VCs in other zones are invisibile. */
1201 		if (vcp->vc_zoneid != zoneid)
1202 			continue;
1203 
1204 		SMB_VC_LOCK(vcp);
1205 
1206 		/* var, head, next_field */
1207 		SLIST_FOREACH(coss, &(VCTOCP(vcp)->co_children), co_next) {
1208 			nshares++;
1209 		}
1210 
1211 		SMB_VC_UNLOCK(vcp);
1212 	}
1213 	SMB_CO_UNLOCK(&smb_vclist);
1214 
1215 	return (nshares);
1216 }
1217 
1218 /*
1219  * Solaris zones support
1220  */
1221 /*ARGSUSED*/
1222 void
1223 lingering_vc(struct smb_vc *vc)
1224 {
1225 	/* good place for a breakpoint */
1226 	DEBUG_ENTER("lingering VC");
1227 }
1228 
1229 /*
1230  * On zone shutdown, kill any IOD threads still running in this zone.
1231  */
1232 /* ARGSUSED */
1233 void
1234 nsmb_zone_shutdown(zoneid_t zoneid, void *data)
1235 {
1236 	struct smb_connobj *co;
1237 	struct smb_vc *vcp;
1238 
1239 	SMB_CO_LOCK(&smb_vclist);
1240 	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
1241 		vcp = CPTOVC(co);
1242 
1243 		if (vcp->vc_zoneid != zoneid)
1244 			continue;
1245 
1246 		/*
1247 		 * This will close the connection, and
1248 		 * cause the IOD thread to terminate.
1249 		 */
1250 		smb_vc_kill(vcp);
1251 	}
1252 	SMB_CO_UNLOCK(&smb_vclist);
1253 }
1254 
1255 /*
1256  * On zone destroy, kill any IOD threads and free all resources they used.
1257  */
1258 /* ARGSUSED */
1259 void
1260 nsmb_zone_destroy(zoneid_t zoneid, void *data)
1261 {
1262 	struct smb_connobj *co;
1263 	struct smb_vc *vcp;
1264 
1265 	/*
1266 	 * We will repeat what should have already happened
1267 	 * in zone_shutdown to make things go away.
1268 	 *
1269 	 * There should have been an smb_vc_rele call
1270 	 * by now for all VCs in the zone.  If not,
1271 	 * there's probably more we needed to do in
1272 	 * the shutdown call.
1273 	 */
1274 
1275 	SMB_CO_LOCK(&smb_vclist);
1276 
1277 	if (smb_vclist.co_usecount > 1) {
1278 		SMBERROR("%d connections still active\n",
1279 		    smb_vclist.co_usecount - 1);
1280 	}
1281 
1282 	/* var, head, next_field */
1283 	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
1284 		vcp = CPTOVC(co);
1285 
1286 		if (vcp->vc_zoneid != zoneid)
1287 			continue;
1288 
1289 		/* Debugging */
1290 		lingering_vc(vcp);
1291 	}
1292 
1293 	SMB_CO_UNLOCK(&smb_vclist);
1294 }
1295