1/*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *    This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35
36/*
37 * Connection engine.
38 */
39
40#include <sys/sysctl.h>			/* can't avoid that */
41
42#include <sys/smb_apple.h>
43#include <sys/kauth.h>
44
45#include <netsmb/smb.h>
46#include <netsmb/smb_2.h>
47#include <netsmb/smb_subr.h>
48#include <netsmb/smb_conn.h>
49#include <netsmb/smb_dev.h>
50#include <netsmb/smb_tran.h>
51#include <netsmb/smb_trantcp.h>
52#include <netsmb/smb_gss.h>
53#include <netsmb/netbios.h>
54
55extern uint32_t smbfs_deadtimer;
56
57static struct smb_connobj smb_vclist;
58static int smb_vcnext = 1;	/* next unique id for VC */
59
60extern struct linker_set sysctl_net_smb;
61
62SYSCTL_DECL(_net_smb);
63
64SYSCTL_NODE(_net, OID_AUTO, smb, CTLFLAG_RW, NULL, "SMB protocol");
65
66static void smb_co_put(struct smb_connobj *cp, vfs_context_t context);
67
68/*
69 * The smb_co_lock, smb_co_unlock, smb_co_ref, smb_co_rel and smb_co_put deal
70 * with the vclist, vc and shares. So the vclist owns the vc which owns the share.
71 * Currently the share owns nothing even though it does have some relationship
72 * with mount structure.
73 */
74static int smb_co_lock(struct smb_connobj *cp)
75{
76
77	if (cp->co_flags & SMBO_GONE)
78		return EBUSY;
79	if (cp->co_lockowner == current_thread()) {
80		cp->co_lockcount++;
81	} else  {
82		lck_mtx_lock(cp->co_lock);
83		/* We got the lock, but  the VC is going away, so unlock it return EBUSY */
84		if (cp->co_flags & SMBO_GONE) {
85			lck_mtx_unlock(cp->co_lock);
86			return EBUSY;
87		}
88		cp->co_lockowner = current_thread();
89		cp->co_lockcount = 1;
90	}
91	return (0);
92}
93
94static void smb_co_unlock(struct smb_connobj *cp)
95{
96	if (cp->co_lockowner && (cp->co_lockowner != current_thread())) {
97		SMBERROR("not owner of lock");
98	} else if (cp->co_lockcount && (--cp->co_lockcount == 0)) {
99		cp->co_lockowner = NULL;
100		lck_mtx_unlock(cp->co_lock);
101		lck_mtx_lock(&(cp)->co_interlock);
102		if (cp->co_lock_flags & SMBFS_CO_LOCK_WAIT){
103			cp->co_lock_flags &= ~SMBFS_CO_LOCK_WAIT;
104			lck_mtx_unlock(&(cp)->co_interlock);
105			wakeup(&cp->co_lock);
106		} else
107			lck_mtx_unlock(&(cp)->co_interlock);
108	}
109}
110
111/*
112 * Common code for connection object
113 */
114static void
115smb_co_init(struct smb_connobj *cp, int level, const char *objname, struct proc *p)
116{
117#pragma unused (objname, p)
118	SLIST_INIT(&cp->co_children);
119	lck_mtx_init(&cp->co_interlock, co_lck_group, co_lck_attr);
120	cp->co_lock	= lck_mtx_alloc_init(co_lck_group, co_lck_attr);
121	cp->co_lock_flags = 0;
122	cp->co_lockowner = 0;
123	cp->co_lockcount = 0;
124
125	cp->co_level = level;
126	cp->co_usecount = 1;
127	KASSERT(smb_co_lock(cp) == 0,
128			("smb_co_init: lock failed"));
129}
130
131static void smb_co_done(struct smb_connobj *cp)
132{
133	lck_mtx_destroy(&cp->co_interlock, co_lck_group);
134	lck_mtx_free(cp->co_lock, co_lck_group);
135	cp->co_lock = 0;
136	cp->co_lock_flags = 0;
137	cp->co_lockowner = 0;
138	cp->co_lockcount = 0;
139}
140
141static void smb_co_gone(struct smb_connobj *cp, vfs_context_t context)
142{
143	struct smb_connobj *parent;
144
145	/* Drain any locks that are still held */
146	lck_mtx_lock(&(cp)->co_interlock);
147	while (cp->co_lockcount > 0) {
148		cp->co_lock_flags |= SMBFS_CO_LOCK_WAIT;
149		msleep(&cp->co_lock, &(cp)->co_interlock, 0, 0, 0);
150	}
151	lck_mtx_unlock(&(cp)->co_interlock);
152	/*
153	 * The old code would take a smb_co_lock here. Since SMBO_GONE is set
154	 * the smb_co_lock did nothing. So I removed that code.
155	 */
156
157	if (cp->co_gone)
158		cp->co_gone(cp, context);
159	parent = cp->co_parent;
160	if (parent) {
161		if (smb_co_lock(parent)) {
162			SMBERROR("unable to lock level %d\n", parent->co_level);
163		} else {
164			SLIST_REMOVE(&parent->co_children, cp, smb_connobj,
165						 co_next);
166			smb_co_put(parent, context);
167		}
168	}
169	if (cp->co_free)
170		cp->co_free(cp);
171}
172
173static void smb_co_put(struct smb_connobj *cp, vfs_context_t context)
174{
175
176	lck_mtx_lock(&(cp)->co_interlock);
177	if (cp->co_usecount > 1) {
178		cp->co_usecount--;
179	} else if (cp->co_usecount == 1) {
180		cp->co_usecount--;
181		cp->co_flags |= SMBO_GONE;
182	} else {
183		SMBERROR("negative usecount\n");
184	}
185	lck_mtx_unlock(&(cp)->co_interlock);
186	smb_co_unlock(cp);
187	if ((cp->co_flags & SMBO_GONE) == 0)
188		return;
189
190	smb_co_gone(cp, context);
191}
192
193static void smb_co_ref(struct smb_connobj *cp)
194{
195	lck_mtx_lock(&(cp)->co_interlock);
196	if (cp->co_flags & SMBO_GONE) {
197		/*
198		 * This can happen when we are doing a tree disconnect or a VC log off.
199		 * In the future we could fix the tree disconnect by only taking a reference
200		 * on the VC. Not sure what to do about the VC. If we could solve those
201		 * two issues then we should make this a fatal error.
202		 */
203		SMBDEBUG("The object is in the gone state level = 0x%x\n",cp->co_level);
204	}
205	cp->co_usecount++;
206	lck_mtx_unlock(&(cp)->co_interlock);
207}
208
209static void smb_co_addchild(struct smb_connobj *parent, struct smb_connobj *child)
210{
211	smb_co_ref(parent);
212	SLIST_INSERT_HEAD(&parent->co_children, child, co_next);
213	child->co_parent = parent;
214}
215
216static void smb_co_rele(struct smb_connobj *cp, vfs_context_t context)
217{
218	lck_mtx_lock(&(cp)->co_interlock);
219	if (cp->co_usecount > 1) {
220		cp->co_usecount--;
221		lck_mtx_unlock(&(cp)->co_interlock);
222		return;
223	}
224	if (cp->co_usecount == 0) {
225		SMBERROR("negative co_usecount for level %d\n", cp->co_level);
226		lck_mtx_unlock(&(cp)->co_interlock);
227		return;
228	}
229	cp->co_usecount--;
230	if (cp->co_flags & SMBO_GONE) {
231		lck_mtx_unlock(&(cp)->co_interlock);
232		return; /* someone is already draining */
233	}
234	cp->co_flags |= SMBO_GONE;
235	lck_mtx_unlock(&(cp)->co_interlock);
236
237	smb_co_gone(cp, context);
238}
239
240struct sockaddr *
241smb_dup_sockaddr(struct sockaddr *sa, int canwait)
242{
243	struct sockaddr *sa2;
244
245	SMB_MALLOC(sa2, struct sockaddr *, sa->sa_len, M_SONAME,
246	       canwait ? M_WAITOK : M_NOWAIT);
247	if (sa2)
248		bcopy(sa, sa2, sa->sa_len);
249	return (sa2);
250}
251
252int smb_sm_init(void)
253{
254	smb_co_init(&smb_vclist, SMBL_VCLIST, "smb_vclist", current_proc());
255	smb_co_unlock(&smb_vclist);
256	return (0);
257}
258
259int smb_sm_done(void)
260{
261	if (smb_vclist.co_usecount > 1) {
262		SMBERROR("%d connections still active\n", smb_vclist.co_usecount - 1);
263		return (EBUSY);
264	}
265	/* XXX Q4BP why are we not iterating on smb_vclist here with SMBCO_FOREACH? */
266	smb_co_done(&smb_vclist);
267	return (0);
268}
269
270static void smb_sm_lockvclist()
271{
272  	/*
273	 * The smb_vclist never goes away so there is no way for smb_co_lock
274	 * to fail in this case.
275	 */
276	KASSERT((smb_co_lock(&smb_vclist) == 0), ("smb_sm_lockvclist: lock failed"));
277}
278
279static void smb_sm_unlockvclist()
280{
281	smb_co_unlock(&smb_vclist);
282}
283
284/*
285 * This routine will reset the virtual circuit. When doing a reconnect we need to
286 * keep some of the virtual circuit information around. We only reset the information
287 * that is required to do the reconnect.
288 */
289void smb_vc_reset(struct smb_vc *vcp)
290{
291	/*
292	 * If these three flags were set keep them for the reconnect. Clear out
293	 * any other flags that may have been set in the original connection.
294	 */
295	vcp->vc_hflags2 &= (SMB_FLAGS2_EXT_SEC | SMB_FLAGS2_KNOWS_LONG_NAMES | SMB_FLAGS2_UNICODE);
296
297	vcp->vc_mid = 0;
298	vcp->vc_low_pid = 1;
299
300    vcp->vc_message_id = 1;
301
302    /* leave vc_misc_flags untouched as it has preferences flags */
303    //vcp->vc_misc_flags = 0;
304
305    /* Save previous sessID for reconnects SessionSetup request */
306    vcp->vc_prev_session_id = vcp->vc_session_id;
307    vcp->vc_session_id = 0;
308
309	vcp->vc_number = smb_vcnext++;
310
311	/* Reset the smb signing */
312	smb_reset_sig(vcp);
313}
314
315void smb_vc_ref(struct smb_vc *vcp)
316{
317	smb_co_ref(VCTOCP(vcp));
318}
319
320void smb_vc_rele(struct smb_vc *vcp, vfs_context_t context)
321{
322	smb_co_rele(VCTOCP(vcp), context);
323}
324
325static void smb_vc_put(struct smb_vc *vcp, vfs_context_t context)
326{
327	smb_co_put(VCTOCP(vcp), context);
328}
329
330int smb_vc_lock(struct smb_vc *vcp)
331{
332	return smb_co_lock(VCTOCP(vcp));
333}
334
335void smb_vc_unlock(struct smb_vc *vcp)
336{
337	smb_co_unlock(VCTOCP(vcp));
338}
339
340static void smb_vc_free(struct smb_connobj *cp)
341{
342	struct smb_vc *vcp = (struct smb_vc*)cp;
343
344	smb_gss_rel_cred(vcp);
345
346	if (vcp->vc_iod)
347		smb_iod_destroy(vcp->vc_iod);
348	vcp->vc_iod = NULL;
349
350    if (vcp->negotiate_token) {
351        SMB_FREE(vcp->negotiate_token, M_SMBTEMP);
352    }
353
354    if (vcp->NativeOS) {
355        SMB_FREE(vcp->NativeOS, M_SMBSTR);
356    }
357
358    if (vcp->NativeLANManager) {
359        SMB_FREE(vcp->NativeLANManager, M_SMBSTR);
360    }
361
362    if (vcp->vc_username) {
363        SMB_FREE(vcp->vc_username, M_SMBSTR);
364    }
365
366    if (vcp->vc_srvname) {
367        SMB_FREE(vcp->vc_srvname, M_SMBSTR);
368    }
369
370    if (vcp->vc_localname) {
371        SMB_FREE(vcp->vc_localname, M_SMBSTR);
372    }
373
374    if (vcp->vc_pass) {
375        SMB_FREE(vcp->vc_pass, M_SMBSTR);
376    }
377
378    if (vcp->vc_domain) {
379        SMB_FREE(vcp->vc_domain, M_SMBSTR);
380    }
381
382	if (vcp->vc_mackey) {
383		SMB_FREE(vcp->vc_mackey, M_SMBTEMP);
384    }
385
386    if (vcp->vc_saddr) {
387		SMB_FREE(vcp->vc_saddr, M_SONAME);
388    }
389
390    if (vcp->vc_laddr) {
391		SMB_FREE(vcp->vc_laddr, M_SONAME);
392    }
393
394	smb_gss_destroy(&vcp->vc_gss);
395
396	if (vcp->throttle_info)
397		throttle_info_release(vcp->throttle_info);
398	vcp->throttle_info = NULL;
399
400	if (vcp->vc_model_info) {
401		SMB_FREE(vcp->vc_model_info, M_SMBTEMP);
402    }
403
404    smb_co_done(VCTOCP(vcp));
405	lck_mtx_destroy(&vcp->vc_stlock, vcst_lck_group);
406    if (vcp) {
407        SMB_FREE(vcp, M_SMBCONN);
408    }
409}
410
411/*
412 * Force reconnect on vc
413 */
414int smb_vc_force_reconnect(struct smb_vc *vcp)
415{
416	if (vcp->vc_iod) {
417		smb_iod_request(vcp->vc_iod, SMBIOD_EV_FORCE_RECONNECT | SMBIOD_EV_SYNC, NULL);
418    }
419
420	return (0);
421}
422
423/*
424 * Destroy VC to server, invalidate shares linked with it.
425 * Transport should be locked on entry.
426 */
427static int smb_vc_disconnect(struct smb_vc *vcp)
428{
429	if (vcp->vc_iod)
430		smb_iod_request(vcp->vc_iod, SMBIOD_EV_DISCONNECT | SMBIOD_EV_SYNC, NULL);
431	return (0);
432}
433
434/*
435 * Called when use count of VC dropped to zero.
436 * VC should be locked on enter with LK_DRAIN.
437 */
438static void smb_vc_gone(struct smb_connobj *cp, vfs_context_t context)
439{
440#pragma unused(context)
441	struct smb_vc *vcp = (struct smb_vc*)cp;
442	smb_vc_disconnect(vcp);
443}
444
445static int smb_vc_create(struct smbioc_negotiate *vcspec,
446						 struct sockaddr *saddr, struct sockaddr *laddr,
447						 vfs_context_t context, struct smb_vc **vcpp)
448{
449	struct smb_vc *vcp;
450	int error = 0;
451
452	/* Should never happen, but just to be safe */
453	if (context == NULL) {
454		return ENOTSUP;
455	}
456	SMB_MALLOC(vcp, struct smb_vc *, sizeof(*vcp), M_SMBCONN, M_WAITOK | M_ZERO);
457	smb_co_init(VCTOCP(vcp), SMBL_VC, "smb_vc", vfs_context_proc(context));
458	vcp->obj.co_free = smb_vc_free;
459	vcp->obj.co_gone = smb_vc_gone;
460	vcp->vc_number = smb_vcnext++;
461	vcp->vc_timo = SMB_DEFRQTIMO;
462	vcp->vc_smbuid = SMB_UID_UNKNOWN;
463	vcp->vc_tdesc = &smb_tran_nbtcp_desc;
464	vcp->vc_seqno = 0;
465	vcp->vc_mackey = NULL;
466	vcp->vc_mackeylen = 0;
467    vcp->vc_smb3_signing_key_len = 0;
468    vcp->vc_smb3_encrypt_key_len = 0;
469    vcp->vc_smb3_decrypt_key_len = 0;
470	vcp->vc_saddr = saddr;
471	vcp->vc_laddr = laddr;
472	/* Remove any user setable items */
473	vcp->vc_flags &= ~SMBV_USER_LAND_MASK;
474	/* Now add the users setable items */
475	vcp->vc_flags |= (vcspec->ioc_userflags & SMBV_USER_LAND_MASK);
476
477	/* Now add the throttle info */
478	vcp->throttle_info = throttle_info_create();
479#ifdef DEBUG_TURN_OFF_EXT_SEC
480	vcp->vc_hflags2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
481#else // DEBUG_TURN_OFF_EXT_SEC
482	vcp->vc_hflags2 = SMB_FLAGS2_KNOWS_LONG_NAMES | SMB_FLAGS2_EXT_SEC | SMB_FLAGS2_UNICODE;
483#endif // DEBUG_TURN_OFF_EXT_SEC
484
485	vcp->vc_uid = vcspec->ioc_ssn.ioc_owner;
486	vcp->vc_gss.gss_asid = AU_ASSIGN_ASID;
487
488	/* Amount of time to wait while reconnecting */
489	vcp->reconnect_wait_time = vcspec->ioc_ssn.ioc_reconnect_wait_time;
490
491    lck_mtx_init(&vcp->vc_credits_lock, vc_credits_lck_group, vc_credits_lck_attr);
492
493	lck_mtx_init(&vcp->vc_stlock, vcst_lck_group, vcst_lck_attr);
494
495	vcp->vc_srvname = smb_strndup(vcspec->ioc_ssn.ioc_srvname, sizeof(vcspec->ioc_ssn.ioc_srvname));
496	if (vcp->vc_srvname)
497		vcp->vc_localname = smb_strndup(vcspec->ioc_ssn.ioc_localname,  sizeof(vcspec->ioc_ssn.ioc_localname));
498	if ((vcp->vc_srvname == NULL) || (vcp->vc_localname == NULL)) {
499		error = ENOMEM;
500	}
501
502	vcp->vc_message_id = 1;
503    vcp->vc_misc_flags = SMBV_HAS_FILEIDS;  /* assume File IDs supported */
504    vcp->vc_server_caps = 0;
505	vcp->vc_volume_caps = 0;
506	vcp->vc_model_info = NULL;
507
508	if (!error)
509		error = smb_iod_create(vcp);
510	if (error) {
511		smb_vc_put(vcp, context);
512		return error;
513	}
514	*vcpp = vcp;
515
516	/* is SMB 1 or SMB 2/3 only flags set? */
517	if (vcspec->ioc_extra_flags & SMB_SMB1_ONLY) {
518		vcp->vc_misc_flags |= SMBV_NEG_SMB1_ONLY;
519	}
520	else if (vcspec->ioc_extra_flags & SMB_SMB2_ONLY) {
521		vcp->vc_misc_flags |= SMBV_NEG_SMB2_ONLY;
522	}
523    else if (vcspec->ioc_extra_flags & SMB_SMB3_ONLY) {
524		vcp->vc_misc_flags |= SMBV_NEG_SMB3_ONLY;
525	}
526
527	if (vcspec->ioc_extra_flags & SMB_SIGNING_REQUIRED) {
528		vcp->vc_misc_flags |= SMBV_CLIENT_SIGNING_REQUIRED;
529	}
530
531	/* Save client Guid */
532	memcpy(vcp->vc_client_guid, vcspec->ioc_client_guid, sizeof(vcp->vc_client_guid));
533
534    /* Set default max amount of time to wait for any response from server */
535    if ((vcspec->ioc_max_resp_timeout != 0) &&
536        (vcspec->ioc_max_resp_timeout <= 600)) {
537        vcp->vc_resp_wait_timeout = vcspec->ioc_max_resp_timeout;
538        SMBWARNING("vc_resp_wait_timeout changed from default to %d \n", vcp->vc_resp_wait_timeout);
539    }
540    else {
541        vcp->vc_resp_wait_timeout = SMB_RESP_WAIT_TIMO;
542    }
543
544	smb_sm_lockvclist();
545	smb_co_addchild(&smb_vclist, VCTOCP(vcp));
546	smb_sm_unlockvclist();
547	return 0;
548}
549
550/*
551 * So we have three types of sockaddr strcutures, IPv4, IPv6 or NetBIOS.
552 *
553 * If both sa_family equal AF_NETBIOS then we can just compare the two sockaddr
554 * structures.
555 *
556 * If neither sa_family equal AF_NETBIOS then we can just compare the two sockaddr
557 * structures.
558 *
559 * If the search sa_family equal AF_NETBIOS and the vc sa_family doesn't then we
560 * can just compare, since its its not going to match. We never support sharing
561 * a AF_NETBIOS with a non AF_NETBIOS connection.
562 *
563 * Now that just leaves the cases were the VC is connected using AF_NETBIOS and
564 * the search sockaddr is either IPv4 or IPv6. We need to compare using the real
565 * sockaddr that is inside the AF_NETBIOS sockaddr_nb structure.
566 */
567static int addressMatch(struct smb_vc *vcp, struct sockaddr *saddr)
568{
569	struct sockaddr *vc_saddr = vcp->vc_saddr;
570
571	if ((vc_saddr->sa_family == AF_NETBIOS) && (saddr->sa_family != AF_NETBIOS)) {
572		vc_saddr = (struct sockaddr *)&((struct sockaddr_nb *)vcp->vc_saddr)->snb_addrin;
573	}
574
575	if ((vc_saddr->sa_len == saddr->sa_len) && (memcmp(vc_saddr, saddr, saddr->sa_len) == 0))
576		return TRUE;
577
578	return FALSE;
579}
580
581/*
582 * On success the vc will have a reference taken and a lock.
583 *
584 * Only smb_sm_negotiate passes sockaddr, all other routines need to pass in a
585 * vcp to search on.
586 */
587static int smb_sm_lookupint(struct sockaddr *sap, uid_t owner, char *username,
588							uint32_t user_flags, struct smb_vc **vcpp)
589{
590	struct smb_vc *vcp, *tvcp;
591	int error;
592
593
594	DBG_ASSERT(vcpp);	/* Better have passed us a vcpp */
595tryagain:
596	smb_sm_lockvclist();
597	error = ENOENT;
598	SMBCO_FOREACH_SAFE(vcp, &smb_vclist, tvcp) {
599
600		if (*vcpp && vcp != *vcpp)
601			continue;
602		else if (*vcpp) {
603			/* Found a match, lock it, we are done. */
604			error = smb_vc_lock(vcp);
605            if (error != 0) {
606                /* Can happen with bad servers */
607                SMBDEBUG("smb_vc_lock returned error %d\n", error);
608            }
609			break;
610		} else {
611			/*
612			 * We should only get in here from the negotiate routine. We better
613			 * have a sock addr or thats a programming error.
614			 */
615			DBG_ASSERT(sap);
616
617			/* Don't share a vcp that hasn't been authenticated yet */
618			if ((vcp->vc_flags & SMBV_AUTH_DONE) != SMBV_AUTH_DONE) {
619				continue;
620			}
621
622			/* The sock address structure needs to match. */
623			if (!addressMatch(vcp, sap)) {
624				continue;
625			}
626
627			/* Must be the same owner */
628			if (vcp->vc_uid != owner) {
629				continue;
630			}
631
632			/* Ok we have a lock on the vcp, any error needs to unlock it */
633			error = smb_vc_lock(vcp);
634			/*
635			 * This VC is going away, but it is currently block on the lock we
636			 * hold for smb_vclist. We need to unlock the list and allow the VC
637			 * to be remove. This still may not be the VC we were looking for so
638			 * start the search again.
639			 */
640			if (error) {
641				smb_sm_unlockvclist();
642				goto tryagain;
643			}
644
645			/*
646			 * The VC must be active and not in reconnect, otherwise we should
647			 * just skip this VC.
648			 */
649			if ((vcp->vc_iod->iod_state != SMBIOD_ST_VCACTIVE) ||
650				(vcp->vc_iod->iod_flags & SMBIOD_RECONNECT)) {
651				SMBWARNING("Skipping %s because its down or in reconnect: flags = 0x%x state = 0x%x\n",
652						   vcp->vc_srvname, vcp->vc_iod->iod_flags, vcp->vc_iod->iod_state);
653				smb_vc_unlock(vcp);
654				error = ENOENT;
655				continue;
656			}
657
658			/*
659			 * If they ask for authentication then the VC needs to match that
660			 * authentication or we need to keep looking. So here are the
661			 * scenarios we need to deal with here.
662			 *
663			 * 1. If they are asking for a private guest access and the VC has
664			 *    private guest access set then use this VC. If either is set,
665			 *    but not both then don't reuse the VC.
666			 * 2. If they are asking for a anonymous access and the VC has
667			 *    anonymous access set then use this VC. If either is set,
668			 *    but not both then don't reuse the VC.
669			 * 3. They are requesting kerberos access. If the current VC isn't
670			 *    using kerberos then don't reuse the vcp.
671			 * 4. They are requesting guest access. If the current VC isn't
672			 *    using guest then don't reuse the VC.
673			 * 4. They are using user level security. The VC user name needs to
674			 *	  match the one passed in.
675			 * 4. They don't care. Always use the authentication of this VC.
676			 */
677			if ((vcp->vc_flags & SMBV_SFS_ACCESS)) {
678				/* We're guest no matter what the user says, just use this VC */
679				error = 0;
680				break;
681			} else if ((user_flags & SMBV_PRIV_GUEST_ACCESS) || (vcp->vc_flags & SMBV_PRIV_GUEST_ACCESS)) {
682				if ((user_flags & SMBV_PRIV_GUEST_ACCESS) && (vcp->vc_flags & SMBV_PRIV_GUEST_ACCESS)) {
683					error = 0;
684					break;
685				} else {
686					smb_vc_unlock(vcp);
687					error = ENOENT;
688					continue;
689				}
690			} else if ((user_flags & SMBV_ANONYMOUS_ACCESS) || (vcp->vc_flags & SMBV_ANONYMOUS_ACCESS)) {
691				if ((user_flags & SMBV_ANONYMOUS_ACCESS) && (vcp->vc_flags & SMBV_ANONYMOUS_ACCESS)) {
692					error = 0;
693					break;
694				} else {
695					smb_vc_unlock(vcp);
696					error = ENOENT;
697					continue;
698				}
699			} else if (user_flags & SMBV_KERBEROS_ACCESS) {
700				if (vcp->vc_flags & SMBV_KERBEROS_ACCESS) {
701					error = 0;
702					break;
703				} else {
704					smb_vc_unlock(vcp);
705					error = ENOENT;
706					continue;
707				}
708			} else if (user_flags & SMBV_GUEST_ACCESS) {
709				if (vcp->vc_flags & SMBV_GUEST_ACCESS) {
710					error = 0;
711					break;
712				} else {
713					smb_vc_unlock(vcp);
714					error = ENOENT;
715					continue;
716				}
717			} else if (username && username[0]) {
718				if (vcp->vc_username &&
719					((strncmp(vcp->vc_username, username, SMB_MAXUSERNAMELEN + 1)) == 0)) {
720					error = 0;
721					break;
722				} else {
723					smb_vc_unlock(vcp);
724					error = ENOENT;
725					continue;
726				}
727			}
728			error = 0;
729			break;
730		}
731	}
732	if (vcp && !error) {
733		smb_vc_ref(vcp);
734		*vcpp = vcp;
735	}
736	smb_sm_unlockvclist();
737	return error;
738}
739
740int smb_sm_negotiate(struct smbioc_negotiate *vcspec, vfs_context_t context,
741				 struct smb_vc **vcpp, struct smb_dev *sdp, int searchOnly)
742{
743	struct smb_vc *vcp = NULL;
744	struct sockaddr	*saddr = NULL, *laddr = NULL;
745	int error;
746
747	saddr = smb_memdupin(vcspec->ioc_kern_saddr, vcspec->ioc_saddr_len);
748	if (saddr == NULL) {
749		return ENOMEM;
750	}
751
752	*vcpp = vcp = NULL;
753
754	if (vcspec->ioc_extra_flags & SMB_FORCE_NEW_SESSION) {
755		error = ENOENT;	/* Force a new virtual circuit session */
756	} else {
757		error = smb_sm_lookupint(saddr, vcspec->ioc_ssn.ioc_owner, vcspec->ioc_user,
758							 vcspec->ioc_userflags, &vcp);
759	}
760
761	if ((error == 0) || (searchOnly)) {
762		SMB_FREE(saddr, M_SMBDATA);
763		vcspec->ioc_extra_flags |= SMB_SHARING_VC;
764	} else {
765		/* NetBIOS connections require a local address */
766		if (saddr->sa_family == AF_NETBIOS) {
767			laddr = smb_memdupin(vcspec->ioc_kern_laddr, vcspec->ioc_laddr_len);
768			if (laddr == NULL) {
769				SMB_FREE(saddr, M_SMBDATA);
770				return ENOMEM;
771			}
772		}
773		/* If smb_vc_create fails it will clean up saddr and laddr */
774		error = smb_vc_create(vcspec, saddr, laddr, context, &vcp);
775		if (error == 0) {
776			/* Flags used to cancel the connection */
777			vcp->connect_flag = &sdp->sd_flags;
778			error = smb_vc_negotiate(vcp, context);
779			vcp->connect_flag = NULL;
780			if (error) /* Remove the lock and reference */
781				smb_vc_put(vcp, context);
782		}
783	}
784	if ((error == 0) && (vcp)) {
785		/*
786		 * They don't want us to touch the home directory, remove the flag. This
787		 * will prevent any shared sessions to touch the home directory when they
788		 * shouldn't.
789		 */
790		if ((vcspec->ioc_userflags & SMBV_HOME_ACCESS_OK) != SMBV_HOME_ACCESS_OK) {
791			vcp->vc_flags &= ~SMBV_HOME_ACCESS_OK;
792		}
793		*vcpp = vcp;
794		smb_vc_unlock(vcp);
795	}
796	return error;
797}
798
799int smb_sm_ssnsetup(struct smb_vc *vcp, struct smbioc_setup *sspec,
800					vfs_context_t context)
801{
802	int error;
803
804	/*
805	 * Call smb_sm_lookupint to verify that the vcp is still on the
806	 * list. If not found then something really bad has happen. Log
807	 * it and just return the error. If smb_sm_lookupint returns without
808	 * an error then the vcp will be locked and a refcnt will be taken.
809	 */
810	error = smb_sm_lookupint(NULL, 0, NULL, 0, &vcp);
811	if (error) {
812		SMBERROR("The virtual circtuit was not found: error = %d\n", error);
813		return error;
814	}
815
816	if ((vcp->vc_flags & SMBV_AUTH_DONE) == SMBV_AUTH_DONE)
817		goto done;	/* Nothing more to do here */
818
819	/* Remove any user setable items */
820	vcp->vc_flags &= ~SMBV_USER_LAND_MASK;
821	/* Now add the users setable items */
822	vcp->vc_flags |= (sspec->ioc_userflags & SMBV_USER_LAND_MASK);
823	/*
824	 * Reset the username, password, domain, kerb client and service names. We
825	 * never want to use any values left over from any previous calls.
826	 */
827    if (vcp->vc_username != NULL) {
828        SMB_FREE(vcp->vc_username, M_SMBSTR);
829    }
830    if (vcp->vc_pass != NULL) {
831        SMB_FREE(vcp->vc_pass, M_SMBSTR);
832    }
833    if (vcp->vc_domain != NULL) {
834        SMB_FREE(vcp->vc_domain, M_SMBSTR);
835    }
836    if (vcp->vc_gss.gss_cpn != NULL) {
837        SMB_FREE(vcp->vc_gss.gss_cpn, M_SMBSTR);
838    }
839	/*
840	 * Freeing the SPN will make sure we never use the hint. Remember that the
841	 * gss_spn contains the hint from the negotiate. We now require user
842	 * land to send us a SPN, if we are going to use one.
843	 */
844    if (vcp->vc_gss.gss_spn != NULL) {
845        SMB_FREE(vcp->vc_gss.gss_spn, M_SMBSTR);
846    }
847	vcp->vc_username = smb_strndup(sspec->ioc_user, sizeof(sspec->ioc_user));
848	vcp->vc_pass = smb_strndup(sspec->ioc_password, sizeof(sspec->ioc_password));
849	vcp->vc_domain = smb_strndup(sspec->ioc_domain, sizeof(sspec->ioc_domain));
850
851	if ((vcp->vc_pass == NULL) || (vcp->vc_domain == NULL) ||
852		(vcp->vc_username == NULL)) {
853		error = ENOMEM;
854		goto done;
855	}
856
857	/* GSS principal names are only set if we are doing kerberos or ntlmssp */
858	if (sspec->ioc_gss_client_size) {
859		vcp->vc_gss.gss_cpn = smb_memdupin(sspec->ioc_gss_client_name, sspec->ioc_gss_client_size);
860	}
861	vcp->vc_gss.gss_cpn_len = sspec->ioc_gss_client_size;
862	vcp->vc_gss.gss_client_nt = sspec->ioc_gss_client_nt;
863
864	if (sspec->ioc_gss_target_size) {
865		vcp->vc_gss.gss_spn = smb_memdupin(sspec->ioc_gss_target_name, sspec->ioc_gss_target_size);
866	}
867	vcp->vc_gss.gss_spn_len = sspec->ioc_gss_target_size;
868	vcp->vc_gss.gss_target_nt = sspec->ioc_gss_target_nt;
869	if (!(sspec->ioc_userflags & SMBV_ANONYMOUS_ACCESS)) {
870		SMB_LOG_AUTH("client size = %d client name type = %d\n",
871				   sspec->ioc_gss_client_size, vcp->vc_gss.gss_client_nt);
872		SMB_LOG_AUTH("taget size = %d target name type = %d\n",
873				   sspec->ioc_gss_target_size, vcp->vc_gss.gss_target_nt);
874	}
875
876	error = smb_vc_ssnsetup(vcp);
877	/* If no error then this virtual circuit has been authorized */
878	if (error == 0) {
879		smb_gss_ref_cred(vcp);
880		vcp->vc_flags |= SMBV_AUTH_DONE;
881	}
882
883done:
884	if (error) {
885		/*
886		 * Authorization failed, reset any authorization
887		 * information. This includes removing guest access,
888		 * user name, password and the domain name. We should
889		 * not every return these values after authorization
890		 * fails.
891		 */
892		vcp->vc_flags &= ~(SMBV_GUEST_ACCESS | SMBV_PRIV_GUEST_ACCESS |
893						   SMBV_KERBEROS_ACCESS | SMBV_ANONYMOUS_ACCESS);
894        if (vcp->vc_username) {
895            SMB_FREE(vcp->vc_username, M_SMBSTR);
896        }
897        if (vcp->vc_pass) {
898            SMB_FREE(vcp->vc_pass, M_SMBSTR);
899        }
900        if (vcp->vc_domain) {
901            SMB_FREE(vcp->vc_domain, M_SMBSTR);
902        }
903        if (vcp->vc_gss.gss_cpn) {
904            SMB_FREE(vcp->vc_gss.gss_cpn, M_SMBSTR);
905        }
906        if (vcp->vc_gss.gss_spn) {
907            SMB_FREE(vcp->vc_gss.gss_spn, M_SMBSTR);
908        }
909
910		vcp->vc_gss.gss_spn_len = 0;
911		vcp->vc_gss.gss_cpn_len = 0;
912	}
913
914	/* Release the reference and lock that smb_sm_lookupint took on the vcp */
915	smb_vc_put(vcp, context);
916	return error;
917}
918
919static void smb_share_free(struct smb_connobj *cp)
920{
921	struct smb_share *share = (struct smb_share *)cp;
922
923	SMB_FREE(share->ss_name, M_SMBSTR);
924	lck_mtx_destroy(&share->ss_stlock, ssst_lck_group);
925	lck_mtx_destroy(&share->ss_shlock, ssst_lck_group);
926	lck_mtx_destroy(&share->ss_fid_lock, fid_lck_grp);
927	smb_co_done(SSTOCP(share));
928	SMB_FREE(share, M_SMBCONN);
929}
930
931static void smb_share_gone(struct smb_connobj *cp, vfs_context_t context)
932{
933	struct smb_share *share = (struct smb_share *)cp;
934
935	DBG_ASSERT(share);
936	DBG_ASSERT(SSTOVC(share));
937	DBG_ASSERT(SSTOVC(share)->vc_iod);
938	smb_smb_treedisconnect(share, context);
939}
940
941void smb_share_ref(struct smb_share *share)
942{
943	smb_co_ref(SSTOCP(share));
944}
945
946void smb_share_rele(struct smb_share *share, vfs_context_t context)
947{
948	smb_co_rele(SSTOCP(share), context);
949}
950
951/*
952 * Allocate share structure and attach it to the given VC. The vcp
953 * needs to be locked on entry. Share will be returned in unlocked state,
954 * but will have a reference on it.
955 */
956static int
957smb_share_create(struct smb_vc *vcp, struct smbioc_share *shspec,
958				 struct smb_share **outShare, vfs_context_t context)
959{
960	struct smb_share *share;
961    int i;
962
963	/* Should never happen, but just to be safe */
964	if (context == NULL)
965		return ENOTSUP;
966
967	SMB_MALLOC(share, struct smb_share *, sizeof(*share), M_SMBCONN, M_WAITOK | M_ZERO);
968	if (share == NULL) {
969		return ENOMEM;
970	}
971	share->ss_name = smb_strndup(shspec->ioc_share, sizeof(shspec->ioc_share));
972	if (share->ss_name == NULL) {
973		SMB_FREE(share, M_SMBCONN);
974		return ENOMEM;
975	}
976	/* The smb_co_init routine locks the share and takes a reference */
977	smb_co_init(SSTOCP(share), SMBL_SHARE, "smbss", vfs_context_proc(context));
978	share->obj.co_free = smb_share_free;
979	share->obj.co_gone = smb_share_gone;
980
981    /* alloc FID mapping stuff */
982    lck_mtx_init(&share->ss_fid_lock, fid_lck_grp, fid_lck_attr);
983    for (i = 0; i < SMB_FID_TABLE_SIZE; i++) {
984        LIST_INIT(&share->ss_fid_table[i].fid_list);
985    }
986    share->ss_fid_collisions = 0;
987    share->ss_fid_inserted = 0;
988    share->ss_fid_max_iter = 0;
989
990    lck_mtx_init(&share->ss_shlock, ssst_lck_group, ssst_lck_attr);
991	lck_mtx_init(&share->ss_stlock, ssst_lck_group, ssst_lck_attr);
992	lck_mtx_lock(&share->ss_shlock);
993	share->ss_mount = NULL;	/* Just to be safe clear it out */
994	/* Set the default dead timer */
995	share->ss_dead_timer = smbfs_deadtimer;
996	lck_mtx_unlock(&share->ss_shlock);
997	share->ss_tid = SMB_TID_UNKNOWN;
998	share->ss_tree_id = SMB2_TID_UNKNOWN;
999
1000    /* unlock the share we no longer need the lock */
1001	smb_co_unlock(SSTOCP(share));
1002	smb_co_addchild(VCTOCP(vcp), SSTOCP(share));
1003	*outShare = share;
1004	return (0);
1005}
1006
1007/*
1008 * If we already have a connection on the share take a reference and return.
1009 * Otherwise create the share, add it to the vc list and then do a tree
1010 * connect.
1011 */
1012int smb_sm_tcon(struct smb_vc *vcp, struct smbioc_share *shspec,
1013			struct smb_share **shpp, vfs_context_t context)
1014{
1015	int error;
1016
1017	*shpp = NULL;
1018	/*
1019	 * Call smb_sm_lookupint to verify that the vcp is still on the
1020	 * list. If not found then something really bad has happen. Log
1021	 * it and just return the error. If smb_sm_lookupint returns without
1022	 * an error then the vcp will be locked and a refcnt will be taken.
1023	 */
1024	error = smb_sm_lookupint(NULL, 0, NULL, 0, &vcp);
1025	if (error) {
1026		SMBERROR("The virtual circtuit was not found: error = %d\n", error);
1027		return error;
1028	}
1029	/* At this point we have a locked vcp create the share */
1030    error = smb_share_create(vcp, shspec, shpp, context);
1031    /*
1032     * We hold a lock and reference on the vc. We are done with the vc lock
1033     * so unlock the vc but hold on to the vc references.
1034     */
1035    smb_vc_unlock(vcp);
1036    if (error == 0) {
1037        error = smb_smb_treeconnect(*shpp, context);
1038        if (error) {
1039            /* Let the share drain, so it can get removed */
1040            smb_share_rele(*shpp, context);
1041            *shpp = NULL; /* We failed reset it to NULL */
1042        }
1043    }
1044	if (*shpp && (error == 0)) {
1045		shspec->ioc_optionalSupport = (*shpp)->optionalSupport;
1046        /*
1047         * ioc_fstype will always be 0 at this time because ss_fstype is filled
1048         * in at mount time.
1049         */
1050		shspec->ioc_fstype = (*shpp)->ss_fstype;
1051	}
1052
1053	/* Release the reference that smb_sm_lookupint took on the vc */
1054	smb_vc_rele(vcp, context);
1055	return error;
1056}
1057
1058int smb_vc_access(struct smb_vc *vcp, vfs_context_t context)
1059{
1060	if (SMBV_HAS_GUEST_ACCESS(vcp))
1061		return(0);
1062
1063	/* The smbfs_vnop_strategy routine has no context, we always allow these */
1064	if (context == NULL) {
1065		return(0);
1066	}
1067	if ((vfs_context_suser(context) == 0) ||
1068		(kauth_cred_getuid(vfs_context_ucred(context)) == vcp->vc_uid))
1069		return (0);
1070	return (EACCES);
1071}
1072
1073int smb_vc_negotiate(struct smb_vc *vcp, vfs_context_t context)
1074{
1075	return smb_iod_request(vcp->vc_iod,
1076			       SMBIOD_EV_NEGOTIATE | SMBIOD_EV_SYNC, context);
1077}
1078
1079int smb_vc_ssnsetup(struct smb_vc *vcp)
1080{
1081	return smb_iod_request(vcp->vc_iod,
1082 			       SMBIOD_EV_SSNSETUP | SMBIOD_EV_SYNC, NULL);
1083}
1084
1085static char smb_emptypass[] = "";
1086
1087const char * smb_vc_getpass(struct smb_vc *vcp)
1088{
1089	if (vcp->vc_pass)
1090		return vcp->vc_pass;
1091	return smb_emptypass;
1092}
1093
1094/*
1095 * They are in share level security and the share requires
1096 * a password. Use the vcp password always. On required for
1097 * Windows 98, should drop support someday.
1098 */
1099const char * smb_share_getpass(struct smb_share *share)
1100{
1101	DBG_ASSERT(SSTOVC(share));
1102	return smb_vc_getpass(SSTOVC(share));
1103}
1104
1105/*
1106 * The reconnect code needs to get a reference on the vc. First make sure
1107 * this vc is still in the list and no one has release it yet. If smb_sm_lookupint
1108 * finds it we will have it locked and a reference on it. Next make sure its
1109 * not being release.
1110 */
1111int smb_vc_reconnect_ref(struct smb_vc *vcp, vfs_context_t context)
1112{
1113	int error;
1114
1115	error = smb_sm_lookupint(NULL, 0, NULL, 0, &vcp);
1116	if (error)
1117		return error;
1118
1119	smb_vc_unlock(vcp);
1120	/* This vc is being release just give up */
1121	if (vcp->ss_flags & SMBO_GONE) {
1122		smb_vc_rele(vcp, context);
1123		error = ENOTCONN;
1124	}
1125	return error;
1126}
1127
1128/*
1129 * Called from a thread that is not the main iod thread. Prevents us from
1130 * getting into a deadlock.
1131 */
1132static void smb_reconnect_rel_thread(void *arg)
1133{
1134	struct smbiod *iod = arg;
1135
1136	/* We are done release the reference */
1137	smb_vc_rele(iod->iod_vc, iod->iod_context);
1138}
1139
1140/*
1141 * The reconnect code takes a reference on the vc. So we need to release that
1142 * reference, but if we are the last reference the smb_vc_rele routine will
1143 * attempt to destroy the vc, which will then attempt to destroy the main iod
1144 * thread for the vc. The reconnect code is running under the main iod thread,
1145 * which means we can't destroy the thread from that thread without hanging. So
1146 * start a new thread to just release the reference and do any cleanup required.
1147 * This will be a short live thread that just hangs around long enough to do the
1148 * work required to release the vc reference.
1149 */
1150void smb_vc_reconnect_rel(struct smb_vc *vcp)
1151{
1152	struct smbiod *iod = vcp->vc_iod;
1153	thread_t	thread;
1154	int			error;
1155
1156	do {
1157		error  = kernel_thread_start((thread_continue_t)smb_reconnect_rel_thread,
1158									 iod, &thread);
1159		/*
1160		 * Never expect an error here, but just in case log it, sleep for one
1161		 * second and try again. Nothing else we can do at this point.
1162		 */
1163		if (error) {
1164			struct timespec ts;
1165
1166			SMBERROR("Starting the reconnect vc release thread failed! %d\n",
1167					 error);
1168			ts.tv_sec = 1;
1169			ts.tv_nsec = 0;
1170			msleep(iod, NULL, PWAIT | PCATCH, "smb_vc_reconnect_rel", &ts);
1171		}
1172	} while (error);
1173	thread_deallocate(thread);
1174}
1175
1176
1177