smb_session.c revision 148c5f43199ca0b43fc8e3b643aab11cd66ea327
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24#include <sys/atomic.h>
25#include <sys/strsubr.h>
26#include <sys/synch.h>
27#include <sys/types.h>
28#include <sys/socketvar.h>
29#include <sys/sdt.h>
30#include <smbsrv/netbios.h>
31#include <smbsrv/smb_kproto.h>
32#include <smbsrv/string.h>
33#include <inet/tcp.h>
34
35static volatile uint64_t smb_kids;
36
37uint32_t smb_keep_alive = SSN_KEEP_ALIVE_TIMEOUT;
38
39static void smb_session_cancel(smb_session_t *);
40static int smb_session_message(smb_session_t *);
41static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *,
42    uint8_t *, size_t);
43static smb_user_t *smb_session_lookup_user(smb_session_t *, char *, char *);
44static void smb_session_logoff(smb_session_t *);
45static void smb_request_init_command_mbuf(smb_request_t *sr);
46void dump_smb_inaddr(smb_inaddr_t *ipaddr);
47
48void
49smb_session_timers(smb_session_list_t *se)
50{
51	smb_session_t	*session;
52
53	rw_enter(&se->se_lock, RW_READER);
54	session = list_head(&se->se_act.lst);
55	while (session) {
56		/*
57		 * Walk through the table and decrement each keep_alive
58		 * timer that has not timed out yet. (keepalive > 0)
59		 */
60		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
61		if (session->keep_alive &&
62		    (session->keep_alive != (uint32_t)-1))
63			session->keep_alive--;
64		session = list_next(&se->se_act.lst, session);
65	}
66	rw_exit(&se->se_lock);
67}
68
69void
70smb_session_correct_keep_alive_values(
71    smb_session_list_t	*se,
72    uint32_t		new_keep_alive)
73{
74	smb_session_t		*sn;
75
76	if (new_keep_alive == smb_keep_alive)
77		return;
78	/*
79	 * keep alive == 0 means do not drop connection if it's idle
80	 */
81	smb_keep_alive = (new_keep_alive) ? new_keep_alive : -1;
82
83	/*
84	 * Walk through the table and set each session to the new keep_alive
85	 * value if they have not already timed out.  Block clock interrupts.
86	 */
87	rw_enter(&se->se_lock, RW_READER);
88	sn = list_head(&se->se_rdy.lst);
89	while (sn) {
90		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
91		sn->keep_alive = new_keep_alive;
92		sn = list_next(&se->se_rdy.lst, sn);
93	}
94	sn = list_head(&se->se_act.lst);
95	while (sn) {
96		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
97		if (sn->keep_alive)
98			sn->keep_alive = new_keep_alive;
99		sn = list_next(&se->se_act.lst, sn);
100	}
101	rw_exit(&se->se_lock);
102}
103
104/*
105 * smb_reconnection_check
106 *
107 * This function is called when a client indicates its current connection
108 * should be the only one it has with the server, as indicated by VC=0 in
109 * a SessionSetupX request. We go through the session list and destroy any
110 * stale connections for that client.
111 *
112 * Clients don't associate IP addresses and servers. So a client may make
113 * independent connections (i.e. with VC=0) to a server with multiple
114 * IP addresses. So, when checking for a reconnection, we need to include
115 * the local IP address, to which the client is connecting, when checking
116 * for stale sessions.
117 *
118 * Also check the server's NetBIOS name to support simultaneous access by
119 * multiple clients behind a NAT server.  This will only work for SMB over
120 * NetBIOS on TCP port 139, it will not work SMB over TCP port 445 because
121 * there is no NetBIOS name.  See also Knowledge Base article Q301673.
122 */
123void
124smb_session_reconnection_check(smb_session_list_t *se, smb_session_t *sess)
125{
126	smb_session_t	*sn;
127
128	rw_enter(&se->se_lock, RW_READER);
129	sn = list_head(&se->se_act.lst);
130	while (sn) {
131		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
132		if ((sn != sess) &&
133		    smb_inet_equal(&sn->ipaddr, &sess->ipaddr) &&
134		    smb_inet_equal(&sn->local_ipaddr, &sess->local_ipaddr) &&
135		    (strcasecmp(sn->workstation, sess->workstation) == 0) &&
136		    (sn->opentime <= sess->opentime) &&
137		    (sn->s_kid < sess->s_kid)) {
138			tsignal(sn->s_thread, SIGUSR1);
139		}
140		sn = list_next(&se->se_act.lst, sn);
141	}
142	rw_exit(&se->se_lock);
143}
144
145/*
146 * Send a session message - supports SMB-over-NBT and SMB-over-TCP.
147 *
148 * The mbuf chain is copied into a contiguous buffer so that the whole
149 * message is submitted to smb_sosend as a single request.  This should
150 * help Ethereal/Wireshark delineate the packets correctly even though
151 * TCP_NODELAY has been set on the socket.
152 *
153 * If an mbuf chain is provided, it will be freed and set to NULL here.
154 */
155int
156smb_session_send(smb_session_t *session, uint8_t type, mbuf_chain_t *mbc)
157{
158	smb_txreq_t	*txr;
159	smb_xprt_t	hdr;
160	int		rc;
161
162	switch (session->s_state) {
163	case SMB_SESSION_STATE_DISCONNECTED:
164	case SMB_SESSION_STATE_TERMINATED:
165		if ((mbc != NULL) && (mbc->chain != NULL)) {
166			m_freem(mbc->chain);
167			mbc->chain = NULL;
168			mbc->flags = 0;
169		}
170		return (ENOTCONN);
171	default:
172		break;
173	}
174
175	txr = smb_net_txr_alloc();
176
177	if ((mbc != NULL) && (mbc->chain != NULL)) {
178		rc = mbc_moveout(mbc, (caddr_t)&txr->tr_buf[NETBIOS_HDR_SZ],
179		    sizeof (txr->tr_buf) - NETBIOS_HDR_SZ, &txr->tr_len);
180		if (rc != 0) {
181			smb_net_txr_free(txr);
182			return (rc);
183		}
184	}
185
186	hdr.xh_type = type;
187	hdr.xh_length = (uint32_t)txr->tr_len;
188
189	rc = smb_session_xprt_puthdr(session, &hdr, txr->tr_buf,
190	    NETBIOS_HDR_SZ);
191
192	if (rc != 0) {
193		smb_net_txr_free(txr);
194		return (rc);
195	}
196	txr->tr_len += NETBIOS_HDR_SZ;
197	smb_server_add_txb(session->s_server, (int64_t)txr->tr_len);
198	return (smb_net_txr_send(session->sock, &session->s_txlst, txr));
199}
200
201/*
202 * Read, process and respond to a NetBIOS session request.
203 *
204 * A NetBIOS session must be established for SMB-over-NetBIOS.  Validate
205 * the calling and called name format and save the client NetBIOS name,
206 * which is used when a NetBIOS session is established to check for and
207 * cleanup leftover state from a previous session.
208 *
209 * Session requests are not valid for SMB-over-TCP, which is unfortunate
210 * because without the client name leftover state cannot be cleaned up
211 * if the client is behind a NAT server.
212 */
213static int
214smb_session_request(struct smb_session *session)
215{
216	int			rc;
217	char			*calling_name;
218	char			*called_name;
219	char 			client_name[NETBIOS_NAME_SZ];
220	struct mbuf_chain 	mbc;
221	char 			*names = NULL;
222	smb_wchar_t		*wbuf = NULL;
223	smb_xprt_t		hdr;
224	char *p;
225	int rc1, rc2;
226
227	session->keep_alive = smb_keep_alive;
228
229	if ((rc = smb_session_xprt_gethdr(session, &hdr)) != 0)
230		return (rc);
231
232	DTRACE_PROBE2(receive__session__req__xprthdr, struct session *, session,
233	    smb_xprt_t *, &hdr);
234
235	if ((hdr.xh_type != SESSION_REQUEST) ||
236	    (hdr.xh_length != NETBIOS_SESSION_REQUEST_DATA_LENGTH)) {
237		DTRACE_PROBE1(receive__session__req__failed,
238		    struct session *, session);
239		return (EINVAL);
240	}
241
242	names = kmem_alloc(hdr.xh_length, KM_SLEEP);
243
244	if ((rc = smb_sorecv(session->sock, names, hdr.xh_length)) != 0) {
245		kmem_free(names, hdr.xh_length);
246		DTRACE_PROBE1(receive__session__req__failed,
247		    struct session *, session);
248		return (rc);
249	}
250
251	DTRACE_PROBE3(receive__session__req__data, struct session *, session,
252	    char *, names, uint32_t, hdr.xh_length);
253
254	called_name = &names[0];
255	calling_name = &names[NETBIOS_ENCODED_NAME_SZ + 2];
256
257	rc1 = netbios_name_isvalid(called_name, 0);
258	rc2 = netbios_name_isvalid(calling_name, client_name);
259
260	if (rc1 == 0 || rc2 == 0) {
261
262		DTRACE_PROBE3(receive__invalid__session__req,
263		    struct session *, session, char *, names,
264		    uint32_t, hdr.xh_length);
265
266		kmem_free(names, hdr.xh_length);
267		MBC_INIT(&mbc, MAX_DATAGRAM_LENGTH);
268		(void) smb_mbc_encodef(&mbc, "b",
269		    DATAGRAM_INVALID_SOURCE_NAME_FORMAT);
270		(void) smb_session_send(session, NEGATIVE_SESSION_RESPONSE,
271		    &mbc);
272		return (EINVAL);
273	}
274
275	DTRACE_PROBE3(receive__session__req__calling__decoded,
276	    struct session *, session,
277	    char *, calling_name, char *, client_name);
278
279	/*
280	 * The client NetBIOS name is in oem codepage format.
281	 * We need to convert it to unicode and store it in
282	 * multi-byte format.  We also need to strip off any
283	 * spaces added as part of the NetBIOS name encoding.
284	 */
285	wbuf = kmem_alloc((SMB_PI_MAX_HOST * sizeof (smb_wchar_t)), KM_SLEEP);
286	(void) oemtoucs(wbuf, client_name, SMB_PI_MAX_HOST, OEM_CPG_850);
287	(void) smb_wcstombs(session->workstation, wbuf, SMB_PI_MAX_HOST);
288	kmem_free(wbuf, (SMB_PI_MAX_HOST * sizeof (smb_wchar_t)));
289
290	if ((p = strchr(session->workstation, ' ')) != 0)
291		*p = '\0';
292
293	kmem_free(names, hdr.xh_length);
294	return (smb_session_send(session, POSITIVE_SESSION_RESPONSE, NULL));
295}
296
297/*
298 * Read 4-byte header from the session socket and build an in-memory
299 * session transport header.  See smb_xprt_t definition for header
300 * format information.
301 *
302 * Direct hosted NetBIOS-less SMB (SMB-over-TCP) uses port 445.  The
303 * first byte of the four-byte header must be 0 and the next three
304 * bytes contain the length of the remaining data.
305 */
306int
307smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr)
308{
309	int		rc;
310	unsigned char	buf[NETBIOS_HDR_SZ];
311
312	if ((rc = smb_sorecv(session->sock, buf, NETBIOS_HDR_SZ)) != 0)
313		return (rc);
314
315	switch (session->s_local_port) {
316	case IPPORT_NETBIOS_SSN:
317		ret_hdr->xh_type = buf[0];
318		ret_hdr->xh_length = (((uint32_t)buf[1] & 1) << 16) |
319		    ((uint32_t)buf[2] << 8) |
320		    ((uint32_t)buf[3]);
321		break;
322
323	case IPPORT_SMB:
324		ret_hdr->xh_type = buf[0];
325
326		if (ret_hdr->xh_type != 0) {
327			cmn_err(CE_WARN, "invalid type (%u)", ret_hdr->xh_type);
328			dump_smb_inaddr(&session->ipaddr);
329			return (EPROTO);
330		}
331
332		ret_hdr->xh_length = ((uint32_t)buf[1] << 16) |
333		    ((uint32_t)buf[2] << 8) |
334		    ((uint32_t)buf[3]);
335		break;
336
337	default:
338		cmn_err(CE_WARN, "invalid port %u", session->s_local_port);
339		dump_smb_inaddr(&session->ipaddr);
340		return (EPROTO);
341	}
342
343	return (0);
344}
345
346/*
347 * Encode a transport session packet header into a 4-byte buffer.
348 * See smb_xprt_t definition for header format information.
349 */
350static int
351smb_session_xprt_puthdr(smb_session_t *session, smb_xprt_t *hdr,
352    uint8_t *buf, size_t buflen)
353{
354	if (session == NULL || hdr == NULL ||
355	    buf == NULL || buflen < NETBIOS_HDR_SZ) {
356		return (-1);
357	}
358
359	switch (session->s_local_port) {
360	case IPPORT_NETBIOS_SSN:
361		buf[0] = hdr->xh_type;
362		buf[1] = ((hdr->xh_length >> 16) & 1);
363		buf[2] = (hdr->xh_length >> 8) & 0xff;
364		buf[3] = hdr->xh_length & 0xff;
365		break;
366
367	case IPPORT_SMB:
368		buf[0] = hdr->xh_type;
369		buf[1] = (hdr->xh_length >> 16) & 0xff;
370		buf[2] = (hdr->xh_length >> 8) & 0xff;
371		buf[3] = hdr->xh_length & 0xff;
372		break;
373
374	default:
375		cmn_err(CE_WARN, "invalid port %u", session->s_local_port);
376		dump_smb_inaddr(&session->ipaddr);
377		return (-1);
378	}
379
380	return (0);
381}
382
383static void
384smb_request_init_command_mbuf(smb_request_t *sr)
385{
386	MGET(sr->command.chain, 0, MT_DATA);
387
388	/*
389	 * Setup mbuf, mimic MCLGET but use the complete packet buffer.
390	 */
391	sr->command.chain->m_ext.ext_buf = sr->sr_request_buf;
392	sr->command.chain->m_data = sr->command.chain->m_ext.ext_buf;
393	sr->command.chain->m_len = sr->sr_req_length;
394	sr->command.chain->m_flags |= M_EXT;
395	sr->command.chain->m_ext.ext_size = sr->sr_req_length;
396	sr->command.chain->m_ext.ext_ref = &mclrefnoop;
397
398	/*
399	 * Initialize the rest of the mbuf_chain fields
400	 */
401	sr->command.flags = 0;
402	sr->command.shadow_of = 0;
403	sr->command.max_bytes = sr->sr_req_length;
404	sr->command.chain_offset = 0;
405}
406
407/*
408 * smb_request_cancel
409 *
410 * Handle a cancel for a request properly depending on the current request
411 * state.
412 */
413void
414smb_request_cancel(smb_request_t *sr)
415{
416	mutex_enter(&sr->sr_mutex);
417	switch (sr->sr_state) {
418
419	case SMB_REQ_STATE_SUBMITTED:
420	case SMB_REQ_STATE_ACTIVE:
421	case SMB_REQ_STATE_CLEANED_UP:
422		sr->sr_state = SMB_REQ_STATE_CANCELED;
423		break;
424
425	case SMB_REQ_STATE_WAITING_LOCK:
426		/*
427		 * This request is waiting on a lock.  Wakeup everything
428		 * waiting on the lock so that the relevant thread regains
429		 * control and notices that is has been canceled.  The
430		 * other lock request threads waiting on this lock will go
431		 * back to sleep when they discover they are still blocked.
432		 */
433		sr->sr_state = SMB_REQ_STATE_CANCELED;
434
435		ASSERT(sr->sr_awaiting != NULL);
436		mutex_enter(&sr->sr_awaiting->l_mutex);
437		cv_broadcast(&sr->sr_awaiting->l_cv);
438		mutex_exit(&sr->sr_awaiting->l_mutex);
439		break;
440
441	case SMB_REQ_STATE_WAITING_EVENT:
442	case SMB_REQ_STATE_EVENT_OCCURRED:
443		/*
444		 * Cancellations for these states are handled by the
445		 * notify-change code
446		 */
447		break;
448
449	case SMB_REQ_STATE_COMPLETED:
450	case SMB_REQ_STATE_CANCELED:
451		/*
452		 * No action required for these states since the request
453		 * is completing.
454		 */
455		break;
456	/*
457	 * Cases included:
458	 *	SMB_REQ_STATE_FREE:
459	 *	SMB_REQ_STATE_INITIALIZING:
460	 */
461	default:
462		SMB_PANIC();
463	}
464	mutex_exit(&sr->sr_mutex);
465}
466
467/*
468 * This is the entry point for processing SMB messages over NetBIOS or
469 * SMB-over-TCP.
470 *
471 * NetBIOS connections require a session request to establish a session
472 * on which to send session messages.
473 *
474 * Session requests are not valid on SMB-over-TCP.  We don't need to do
475 * anything here as session requests will be treated as an error when
476 * handling session messages.
477 */
478int
479smb_session_daemon(smb_session_list_t *se)
480{
481	int		rc = 0;
482	smb_session_t	*session;
483
484	session = smb_session_list_activate_head(se);
485	if (session == NULL)
486		return (EINVAL);
487
488	if (session->s_local_port == IPPORT_NETBIOS_SSN) {
489		rc = smb_session_request(session);
490		if (rc) {
491			smb_rwx_rwenter(&session->s_lock, RW_WRITER);
492			session->s_state = SMB_SESSION_STATE_DISCONNECTED;
493			smb_rwx_rwexit(&session->s_lock);
494			smb_session_list_terminate(se, session);
495			return (rc);
496		}
497	}
498
499	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
500	session->s_state = SMB_SESSION_STATE_ESTABLISHED;
501	smb_rwx_rwexit(&session->s_lock);
502
503	rc = smb_session_message(session);
504
505	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
506	session->s_state = SMB_SESSION_STATE_DISCONNECTED;
507	smb_rwx_rwexit(&session->s_lock);
508
509	smb_soshutdown(session->sock);
510
511	DTRACE_PROBE2(session__drop, struct session *, session, int, rc);
512
513	smb_session_cancel(session);
514
515	/*
516	 * At this point everything related to the session should have been
517	 * cleaned up and we expect that nothing will attempt to use the
518	 * socket.
519	 */
520	smb_session_list_terminate(se, session);
521
522	return (rc);
523}
524
525/*
526 * Read and process SMB requests.
527 *
528 * Returns:
529 *	0	Success
530 *	1	Unable to read transport header
531 *	2	Invalid transport header type
532 *	3	Invalid SMB length (too small)
533 *	4	Unable to read SMB header
534 *	5	Invalid SMB header (bad magic number)
535 *	6	Unable to read SMB data
536 *	2x	Write raw failed
537 */
538static int
539smb_session_message(smb_session_t *session)
540{
541	smb_server_t	*sv;
542	smb_request_t	*sr = NULL;
543	smb_xprt_t	hdr;
544	uint8_t		*req_buf;
545	uint32_t	resid;
546	int		rc;
547
548	sv = session->s_server;
549
550	for (;;) {
551
552		rc = smb_session_xprt_gethdr(session, &hdr);
553		if (rc)
554			return (rc);
555
556		DTRACE_PROBE2(session__receive__xprthdr, session_t *, session,
557		    smb_xprt_t *, &hdr);
558
559		if (hdr.xh_type != SESSION_MESSAGE) {
560			/*
561			 * Anything other than SESSION_MESSAGE or
562			 * SESSION_KEEP_ALIVE is an error.  A SESSION_REQUEST
563			 * may indicate a new session request but we need to
564			 * close this session and we can treat it as an error
565			 * here.
566			 */
567			if (hdr.xh_type == SESSION_KEEP_ALIVE) {
568				session->keep_alive = smb_keep_alive;
569				continue;
570			}
571			return (EPROTO);
572		}
573
574		if (hdr.xh_length < SMB_HEADER_LEN)
575			return (EPROTO);
576
577		session->keep_alive = smb_keep_alive;
578		/*
579		 * Allocate a request context, read the SMB header and validate
580		 * it. The sr includes a buffer large enough to hold the SMB
581		 * request payload.  If the header looks valid, read any
582		 * remaining data.
583		 */
584		sr = smb_request_alloc(session, hdr.xh_length);
585
586		req_buf = (uint8_t *)sr->sr_request_buf;
587		resid = hdr.xh_length;
588
589		rc = smb_sorecv(session->sock, req_buf, SMB_HEADER_LEN);
590		if (rc) {
591			smb_request_free(sr);
592			return (rc);
593		}
594
595		if (SMB_PROTOCOL_MAGIC_INVALID(sr)) {
596			smb_request_free(sr);
597			return (EPROTO);
598		}
599
600		if (resid > SMB_HEADER_LEN) {
601			req_buf += SMB_HEADER_LEN;
602			resid -= SMB_HEADER_LEN;
603
604			rc = smb_sorecv(session->sock, req_buf, resid);
605			if (rc) {
606				smb_request_free(sr);
607				return (rc);
608			}
609		}
610		smb_server_add_rxb(sv,
611		    (int64_t)(hdr.xh_length + NETBIOS_HDR_SZ));
612		/*
613		 * Initialize command MBC to represent the received data.
614		 */
615		smb_request_init_command_mbuf(sr);
616
617		DTRACE_PROBE1(session__receive__smb, smb_request_t *, sr);
618
619		/*
620		 * If this is a raw write, hand off the request.  The handler
621		 * will retrieve the remaining raw data and process the request.
622		 */
623		if (SMB_IS_WRITERAW(sr)) {
624			rc = smb_handle_write_raw(session, sr);
625			if (rc == 0)
626				continue;
627			return (rc);
628		}
629		if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
630			if (SMB_IS_NT_CANCEL(sr)) {
631				sr->session->signing.seqnum++;
632				sr->sr_seqnum = sr->session->signing.seqnum + 1;
633				sr->reply_seqnum = 0;
634			} else {
635				sr->session->signing.seqnum += 2;
636				sr->sr_seqnum = sr->session->signing.seqnum;
637				sr->reply_seqnum = sr->sr_seqnum + 1;
638			}
639		}
640		sr->sr_time_submitted = gethrtime();
641		sr->sr_state = SMB_REQ_STATE_SUBMITTED;
642		smb_srqueue_waitq_enter(session->s_srqueue);
643		(void) taskq_dispatch(session->s_server->sv_thread_pool,
644		    smb_session_worker, sr, TQ_SLEEP);
645	}
646}
647
648/*
649 * Port will be IPPORT_NETBIOS_SSN or IPPORT_SMB.
650 */
651smb_session_t *
652smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv,
653    int family)
654{
655	struct sockaddr_in	sin;
656	socklen_t		slen;
657	struct sockaddr_in6	sin6;
658	smb_session_t		*session;
659	int64_t			now;
660
661	session = kmem_cache_alloc(sv->si_cache_session, KM_SLEEP);
662	bzero(session, sizeof (smb_session_t));
663
664	if (smb_idpool_constructor(&session->s_uid_pool)) {
665		kmem_cache_free(sv->si_cache_session, session);
666		return (NULL);
667	}
668
669	now = ddi_get_lbolt64();
670
671	session->s_kid = SMB_NEW_KID();
672	session->s_state = SMB_SESSION_STATE_INITIALIZED;
673	session->native_os = NATIVE_OS_UNKNOWN;
674	session->opentime = now;
675	session->keep_alive = smb_keep_alive;
676	session->activity_timestamp = now;
677
678	smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t),
679	    offsetof(smb_request_t, sr_session_lnd));
680
681	smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t),
682	    offsetof(smb_user_t, u_lnd));
683
684	smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t),
685	    offsetof(smb_xa_t, xa_lnd));
686
687	list_create(&session->s_oplock_brkreqs, sizeof (mbuf_chain_t),
688	    offsetof(mbuf_chain_t, mbc_lnd));
689
690	smb_net_txl_constructor(&session->s_txlst);
691
692	smb_rwx_init(&session->s_lock);
693
694	if (new_so != NULL) {
695		if (family == AF_INET) {
696			slen = sizeof (sin);
697			(void) ksocket_getsockname(new_so,
698			    (struct sockaddr *)&sin, &slen, CRED());
699			bcopy(&sin.sin_addr,
700			    &session->local_ipaddr.au_addr.au_ipv4,
701			    sizeof (in_addr_t));
702			slen = sizeof (sin);
703			(void) ksocket_getpeername(new_so,
704			    (struct sockaddr *)&sin, &slen, CRED());
705			bcopy(&sin.sin_addr,
706			    &session->ipaddr.au_addr.au_ipv4,
707			    sizeof (in_addr_t));
708		} else {
709			slen = sizeof (sin6);
710			(void) ksocket_getsockname(new_so,
711			    (struct sockaddr *)&sin6, &slen, CRED());
712			bcopy(&sin6.sin6_addr,
713			    &session->local_ipaddr.au_addr.au_ipv6,
714			    sizeof (in6_addr_t));
715			slen = sizeof (sin6);
716			(void) ksocket_getpeername(new_so,
717			    (struct sockaddr *)&sin6, &slen, CRED());
718			bcopy(&sin6.sin6_addr,
719			    &session->ipaddr.au_addr.au_ipv6,
720			    sizeof (in6_addr_t));
721		}
722		session->ipaddr.a_family = family;
723		session->local_ipaddr.a_family = family;
724		session->s_local_port = port;
725		session->sock = new_so;
726		if (port == IPPORT_NETBIOS_SSN)
727			smb_server_inc_nbt_sess(sv);
728		else
729			smb_server_inc_tcp_sess(sv);
730	}
731	session->s_server = sv;
732	smb_server_get_cfg(sv, &session->s_cfg);
733	session->s_srqueue = &sv->sv_srqueue;
734
735	session->s_cache_request = sv->si_cache_request;
736	session->s_cache = sv->si_cache_session;
737	session->s_magic = SMB_SESSION_MAGIC;
738	return (session);
739}
740
741void
742smb_session_delete(smb_session_t *session)
743{
744	mbuf_chain_t	*mbc;
745
746	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
747
748	session->s_magic = 0;
749
750	if (session->s_local_port == IPPORT_NETBIOS_SSN)
751		smb_server_dec_nbt_sess(session->s_server);
752	else
753		smb_server_dec_tcp_sess(session->s_server);
754
755	smb_rwx_destroy(&session->s_lock);
756	smb_net_txl_destructor(&session->s_txlst);
757
758	while ((mbc = list_head(&session->s_oplock_brkreqs)) != NULL) {
759		SMB_MBC_VALID(mbc);
760		list_remove(&session->s_oplock_brkreqs, mbc);
761		smb_mbc_free(mbc);
762	}
763	list_destroy(&session->s_oplock_brkreqs);
764
765	smb_slist_destructor(&session->s_req_list);
766	smb_llist_destructor(&session->s_user_list);
767	smb_llist_destructor(&session->s_xa_list);
768
769	ASSERT(session->s_tree_cnt == 0);
770	ASSERT(session->s_file_cnt == 0);
771	ASSERT(session->s_dir_cnt == 0);
772
773	smb_idpool_destructor(&session->s_uid_pool);
774	kmem_cache_free(session->s_cache, session);
775}
776
777static void
778smb_session_cancel(smb_session_t *session)
779{
780	smb_xa_t	*xa, *nextxa;
781
782	/* All the request currently being treated must be canceled. */
783	smb_session_cancel_requests(session, NULL, NULL);
784
785	/*
786	 * We wait for the completion of all the requests associated with
787	 * this session.
788	 */
789	smb_slist_wait_for_empty(&session->s_req_list);
790
791	/*
792	 * At this point the reference count of the users, trees, files,
793	 * directories should be zero. It should be possible to destroy them
794	 * without any problem.
795	 */
796	xa = smb_llist_head(&session->s_xa_list);
797	while (xa) {
798		nextxa = smb_llist_next(&session->s_xa_list, xa);
799		smb_xa_close(xa);
800		xa = nextxa;
801	}
802
803	smb_session_logoff(session);
804}
805
806/*
807 * Cancel requests.  If a non-null tree is specified, only requests specific
808 * to that tree will be cancelled.  If a non-null sr is specified, that sr
809 * will be not be cancelled - this would typically be the caller's sr.
810 */
811void
812smb_session_cancel_requests(
813    smb_session_t	*session,
814    smb_tree_t		*tree,
815    smb_request_t	*exclude_sr)
816{
817	smb_request_t	*sr;
818
819	smb_process_session_notify_change_queue(session, tree);
820
821	smb_slist_enter(&session->s_req_list);
822	sr = smb_slist_head(&session->s_req_list);
823
824	while (sr) {
825		ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
826		if ((sr != exclude_sr) &&
827		    (tree == NULL || sr->tid_tree == tree))
828			smb_request_cancel(sr);
829
830		sr = smb_slist_next(&session->s_req_list, sr);
831	}
832
833	smb_slist_exit(&session->s_req_list);
834}
835
836void
837smb_session_worker(void	*arg)
838{
839	smb_request_t	*sr;
840	smb_srqueue_t	*srq;
841
842	sr = (smb_request_t *)arg;
843	SMB_REQ_VALID(sr);
844
845	srq = sr->session->s_srqueue;
846	smb_srqueue_waitq_to_runq(srq);
847	sr->sr_worker = curthread;
848	mutex_enter(&sr->sr_mutex);
849	sr->sr_time_active = gethrtime();
850	switch (sr->sr_state) {
851	case SMB_REQ_STATE_SUBMITTED:
852		mutex_exit(&sr->sr_mutex);
853		if (smb_dispatch_request(sr)) {
854			mutex_enter(&sr->sr_mutex);
855			sr->sr_state = SMB_REQ_STATE_COMPLETED;
856			mutex_exit(&sr->sr_mutex);
857			smb_request_free(sr);
858		}
859		break;
860
861	default:
862		ASSERT(sr->sr_state == SMB_REQ_STATE_CANCELED);
863		sr->sr_state = SMB_REQ_STATE_COMPLETED;
864		mutex_exit(&sr->sr_mutex);
865		smb_request_free(sr);
866		break;
867	}
868	smb_srqueue_runq_exit(srq);
869}
870
871void
872smb_session_list_constructor(smb_session_list_t *se)
873{
874	bzero(se, sizeof (*se));
875	rw_init(&se->se_lock, NULL, RW_DEFAULT, NULL);
876	list_create(&se->se_rdy.lst, sizeof (smb_session_t),
877	    offsetof(smb_session_t, s_lnd));
878	list_create(&se->se_act.lst, sizeof (smb_session_t),
879	    offsetof(smb_session_t, s_lnd));
880}
881
882void
883smb_session_list_destructor(smb_session_list_t *se)
884{
885	list_destroy(&se->se_rdy.lst);
886	list_destroy(&se->se_act.lst);
887	rw_destroy(&se->se_lock);
888}
889
890void
891smb_session_list_append(smb_session_list_t *se, smb_session_t *session)
892{
893	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
894	ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
895
896	rw_enter(&se->se_lock, RW_WRITER);
897	list_insert_tail(&se->se_rdy.lst, session);
898	se->se_rdy.count++;
899	se->se_wrop++;
900	rw_exit(&se->se_lock);
901}
902
903void
904smb_session_list_delete_tail(smb_session_list_t *se)
905{
906	smb_session_t	*session;
907
908	rw_enter(&se->se_lock, RW_WRITER);
909	session = list_tail(&se->se_rdy.lst);
910	if (session) {
911		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
912		ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
913		list_remove(&se->se_rdy.lst, session);
914		ASSERT(se->se_rdy.count);
915		se->se_rdy.count--;
916		rw_exit(&se->se_lock);
917		smb_session_delete(session);
918		return;
919	}
920	rw_exit(&se->se_lock);
921}
922
923smb_session_t *
924smb_session_list_activate_head(smb_session_list_t *se)
925{
926	smb_session_t	*session;
927
928	rw_enter(&se->se_lock, RW_WRITER);
929	session = list_head(&se->se_rdy.lst);
930	if (session) {
931		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
932		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
933		ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
934		session->s_thread = curthread;
935		session->s_ktdid = session->s_thread->t_did;
936		smb_rwx_rwexit(&session->s_lock);
937		list_remove(&se->se_rdy.lst, session);
938		se->se_rdy.count--;
939		list_insert_tail(&se->se_act.lst, session);
940		se->se_act.count++;
941		se->se_wrop++;
942	}
943	rw_exit(&se->se_lock);
944	return (session);
945}
946
947void
948smb_session_list_terminate(smb_session_list_t *se, smb_session_t *session)
949{
950	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
951
952	rw_enter(&se->se_lock, RW_WRITER);
953
954	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
955	ASSERT(session->s_state == SMB_SESSION_STATE_DISCONNECTED);
956	session->s_state = SMB_SESSION_STATE_TERMINATED;
957	smb_sodestroy(session->sock);
958	session->sock = NULL;
959	smb_rwx_rwexit(&session->s_lock);
960
961	list_remove(&se->se_act.lst, session);
962	se->se_act.count--;
963	se->se_wrop++;
964
965	ASSERT(session->s_thread == curthread);
966
967	rw_exit(&se->se_lock);
968
969	smb_session_delete(session);
970}
971
972/*
973 * smb_session_list_signal
974 *
975 * This function signals all the session threads. The intent is to terminate
976 * them. The sessions still in the SMB_SESSION_STATE_INITIALIZED are delete
977 * immediately.
978 *
979 * This function must only be called by the threads listening and accepting
980 * connections. They must pass in their respective session list.
981 */
982void
983smb_session_list_signal(smb_session_list_t *se)
984{
985	smb_session_t	*session;
986
987	rw_enter(&se->se_lock, RW_WRITER);
988	while (session = list_head(&se->se_rdy.lst)) {
989
990		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
991
992		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
993		ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
994		session->s_state = SMB_SESSION_STATE_TERMINATED;
995		smb_sodestroy(session->sock);
996		session->sock = NULL;
997		smb_rwx_rwexit(&session->s_lock);
998
999		list_remove(&se->se_rdy.lst, session);
1000		se->se_rdy.count--;
1001		se->se_wrop++;
1002
1003		rw_exit(&se->se_lock);
1004		smb_session_delete(session);
1005		rw_enter(&se->se_lock, RW_WRITER);
1006	}
1007	rw_downgrade(&se->se_lock);
1008
1009	session = list_head(&se->se_act.lst);
1010	while (session) {
1011
1012		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1013		tsignal(session->s_thread, SIGUSR1);
1014		session = list_next(&se->se_act.lst, session);
1015	}
1016	rw_exit(&se->se_lock);
1017}
1018
1019/*
1020 * smb_session_lookup_user
1021 */
1022static smb_user_t *
1023smb_session_lookup_user(smb_session_t *session, char *domain, char *name)
1024{
1025	smb_user_t	*user;
1026	smb_llist_t	*ulist;
1027
1028	ulist = &session->s_user_list;
1029	smb_llist_enter(ulist, RW_READER);
1030	user = smb_llist_head(ulist);
1031	while (user) {
1032		ASSERT(user->u_magic == SMB_USER_MAGIC);
1033		if (!smb_strcasecmp(user->u_name, name, 0) &&
1034		    !smb_strcasecmp(user->u_domain, domain, 0)) {
1035			if (smb_user_hold(user))
1036				break;
1037		}
1038		user = smb_llist_next(ulist, user);
1039	}
1040	smb_llist_exit(ulist);
1041
1042	return (user);
1043}
1044
1045/*
1046 * If a user attempts to log in subsequently from the specified session,
1047 * duplicates the existing SMB user instance such that all SMB user
1048 * instances that corresponds to the same user on the given session
1049 * reference the same user's cred.
1050 *
1051 * Returns NULL if the given user hasn't yet logged in from this
1052 * specified session.  Otherwise, returns a user instance that corresponds
1053 * to this subsequent login.
1054 */
1055smb_user_t *
1056smb_session_dup_user(smb_session_t *session, char *domain, char *account_name)
1057{
1058	smb_user_t *orig_user = NULL;
1059	smb_user_t *user = NULL;
1060
1061	orig_user = smb_session_lookup_user(session, domain,
1062	    account_name);
1063
1064	if (orig_user) {
1065		user = smb_user_dup(orig_user);
1066		smb_user_release(orig_user);
1067	}
1068
1069	return (user);
1070}
1071
1072/*
1073 * Find a user on the specified session by SMB UID.
1074 */
1075smb_user_t *
1076smb_session_lookup_uid(smb_session_t *session, uint16_t uid)
1077{
1078	smb_user_t	*user;
1079	smb_llist_t	*user_list;
1080
1081	SMB_SESSION_VALID(session);
1082
1083	user_list = &session->s_user_list;
1084	smb_llist_enter(user_list, RW_READER);
1085
1086	user = smb_llist_head(user_list);
1087	while (user) {
1088		SMB_USER_VALID(user);
1089		ASSERT(user->u_session == session);
1090
1091		if (user->u_uid == uid) {
1092			if (!smb_user_hold(user))
1093				break;
1094
1095			smb_llist_exit(user_list);
1096			return (user);
1097		}
1098
1099		user = smb_llist_next(user_list, user);
1100	}
1101
1102	smb_llist_exit(user_list);
1103	return (NULL);
1104}
1105
1106void
1107smb_session_post_user(smb_session_t *session, smb_user_t *user)
1108{
1109	SMB_USER_VALID(user);
1110	ASSERT(user->u_refcnt == 0);
1111	ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
1112	ASSERT(user->u_session == session);
1113
1114	smb_llist_post(&session->s_user_list, user, smb_user_delete);
1115}
1116
1117/*
1118 * Logoff all users associated with the specified session.
1119 */
1120static void
1121smb_session_logoff(smb_session_t *session)
1122{
1123	smb_user_t	*user;
1124
1125	SMB_SESSION_VALID(session);
1126
1127	smb_llist_enter(&session->s_user_list, RW_READER);
1128
1129	user = smb_llist_head(&session->s_user_list);
1130	while (user) {
1131		SMB_USER_VALID(user);
1132		ASSERT(user->u_session == session);
1133
1134		if (smb_user_hold(user)) {
1135			smb_user_logoff(user);
1136			smb_user_release(user);
1137		}
1138
1139		user = smb_llist_next(&session->s_user_list, user);
1140	}
1141
1142	smb_llist_exit(&session->s_user_list);
1143}
1144
1145/*
1146 * Disconnect any trees associated with the specified share.
1147 * Iterate through the users on this session and tell each user
1148 * to disconnect from the share.
1149 */
1150void
1151smb_session_disconnect_share(smb_session_t *session, const char *sharename)
1152{
1153	smb_user_t	*user;
1154
1155	SMB_SESSION_VALID(session);
1156
1157	smb_llist_enter(&session->s_user_list, RW_READER);
1158
1159	user = smb_llist_head(&session->s_user_list);
1160	while (user) {
1161		SMB_USER_VALID(user);
1162		ASSERT(user->u_session == session);
1163
1164		if (smb_user_hold(user)) {
1165			smb_user_disconnect_share(user, sharename);
1166			smb_user_release(user);
1167		}
1168
1169		user = smb_llist_next(&session->s_user_list, user);
1170	}
1171
1172	smb_llist_exit(&session->s_user_list);
1173}
1174
1175/*
1176 * Copy the session workstation/client name to buf.  If the workstation
1177 * is an empty string (which it will be on TCP connections), use the
1178 * client IP address.
1179 */
1180void
1181smb_session_getclient(smb_session_t *sn, char *buf, size_t buflen)
1182{
1183	char		ipbuf[INET6_ADDRSTRLEN];
1184	smb_inaddr_t	*ipaddr;
1185
1186	ASSERT(sn);
1187	ASSERT(buf);
1188	ASSERT(buflen);
1189
1190	*buf = '\0';
1191
1192	if (sn->workstation[0] != '\0') {
1193		(void) strlcpy(buf, sn->workstation, buflen);
1194		return;
1195	}
1196
1197	ipaddr = &sn->ipaddr;
1198	if (smb_inet_ntop(ipaddr, ipbuf, SMB_IPSTRLEN(ipaddr->a_family)))
1199		(void) strlcpy(buf, ipbuf, buflen);
1200}
1201
1202/*
1203 * Check whether or not the specified client name is the client of this
1204 * session.  The name may be in UNC format (\\CLIENT).
1205 *
1206 * A workstation/client name is setup on NBT connections as part of the
1207 * NetBIOS session request but that isn't available on TCP connections.
1208 * If the session doesn't have a client name we typically return the
1209 * client IP address as the workstation name on MSRPC requests.  So we
1210 * check for the IP address here in addition to the workstation name.
1211 */
1212boolean_t
1213smb_session_isclient(smb_session_t *sn, const char *client)
1214{
1215	char		buf[INET6_ADDRSTRLEN];
1216	smb_inaddr_t	*ipaddr;
1217
1218	client += strspn(client, "\\");
1219
1220	if (smb_strcasecmp(client, sn->workstation, 0) == 0)
1221		return (B_TRUE);
1222
1223	ipaddr = &sn->ipaddr;
1224	if (smb_inet_ntop(ipaddr, buf, SMB_IPSTRLEN(ipaddr->a_family)) == NULL)
1225		return (B_FALSE);
1226
1227	if (smb_strcasecmp(client, buf, 0) == 0)
1228		return (B_TRUE);
1229
1230	return (B_FALSE);
1231}
1232
1233/*
1234 * smb_request_alloc
1235 *
1236 * Allocate an smb_request_t structure from the kmem_cache.  Partially
1237 * initialize the found/new request.
1238 *
1239 * Returns pointer to a request
1240 */
1241smb_request_t *
1242smb_request_alloc(smb_session_t *session, int req_length)
1243{
1244	smb_request_t	*sr;
1245
1246	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1247
1248	sr = kmem_cache_alloc(session->s_cache_request, KM_SLEEP);
1249
1250	/*
1251	 * Future:  Use constructor to pre-initialize some fields.  For now
1252	 * there are so many fields that it is easiest just to zero the
1253	 * whole thing and start over.
1254	 */
1255	bzero(sr, sizeof (smb_request_t));
1256
1257	mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL);
1258	smb_srm_init(sr);
1259	sr->session = session;
1260	sr->sr_server = session->s_server;
1261	sr->sr_gmtoff = session->s_server->si_gmtoff;
1262	sr->sr_cache = session->s_server->si_cache_request;
1263	sr->sr_cfg = &session->s_cfg;
1264	sr->command.max_bytes = req_length;
1265	sr->reply.max_bytes = smb_maxbufsize;
1266	sr->sr_req_length = req_length;
1267	if (req_length)
1268		sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP);
1269	sr->sr_magic = SMB_REQ_MAGIC;
1270	sr->sr_state = SMB_REQ_STATE_INITIALIZING;
1271	smb_slist_insert_tail(&session->s_req_list, sr);
1272	return (sr);
1273}
1274
1275/*
1276 * smb_request_free
1277 *
1278 * release the memories which have been allocated for a smb request.
1279 */
1280void
1281smb_request_free(smb_request_t *sr)
1282{
1283	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
1284	ASSERT(sr->session);
1285	ASSERT(sr->r_xa == NULL);
1286
1287	if (sr->fid_ofile != NULL)
1288		smb_ofile_release(sr->fid_ofile);
1289
1290	if (sr->tid_tree != NULL)
1291		smb_tree_release(sr->tid_tree);
1292
1293	if (sr->uid_user != NULL)
1294		smb_user_release(sr->uid_user);
1295
1296	smb_slist_remove(&sr->session->s_req_list, sr);
1297
1298	sr->session = NULL;
1299
1300	smb_srm_fini(sr);
1301
1302	if (sr->sr_request_buf)
1303		kmem_free(sr->sr_request_buf, sr->sr_req_length);
1304	if (sr->command.chain)
1305		m_freem(sr->command.chain);
1306	if (sr->reply.chain)
1307		m_freem(sr->reply.chain);
1308	if (sr->raw_data.chain)
1309		m_freem(sr->raw_data.chain);
1310
1311	sr->sr_magic = 0;
1312	mutex_destroy(&sr->sr_mutex);
1313	kmem_cache_free(sr->sr_cache, sr);
1314}
1315
1316void
1317dump_smb_inaddr(smb_inaddr_t *ipaddr)
1318{
1319	char ipstr[INET6_ADDRSTRLEN];
1320
1321	if (smb_inet_ntop(ipaddr, ipstr, SMB_IPSTRLEN(ipaddr->a_family)))
1322		cmn_err(CE_WARN, "error ipstr=%s", ipstr);
1323	else
1324		cmn_err(CE_WARN, "error converting ip address");
1325}
1326
1327boolean_t
1328smb_session_oplocks_enable(smb_session_t *session)
1329{
1330	SMB_SESSION_VALID(session);
1331	if (session->s_cfg.skc_oplock_enable == 0)
1332		return (B_FALSE);
1333	else
1334		return (B_TRUE);
1335}
1336
1337/*
1338 * smb_session_breaking_oplock
1339 *
1340 * This MUST be a cross-session call, i.e. the caller must be in a different
1341 * context than the one passed. The mutex of the SMB node requiring an oplock
1342 * break MUST be dropped before calling this function. This last requirement is
1343 * due to a potential deadlock that can occur when trying to enter the lock of
1344 * the session passed in.
1345 */
1346void
1347smb_session_oplock_break(smb_session_t *session, smb_ofile_t *of)
1348{
1349	mbuf_chain_t	*mbc;
1350
1351	SMB_SESSION_VALID(session);
1352
1353	mbc = smb_mbc_alloc(MLEN);
1354
1355	(void) smb_mbc_encodef(mbc, "Mb19.wwwwbb3.ww10.",
1356	    SMB_COM_LOCKING_ANDX,
1357	    SMB_TREE_GET_TID(SMB_OFILE_GET_TREE(of)),
1358	    0xFFFF, 0, 0xFFFF, 8, 0xFF,
1359	    SMB_OFILE_GET_FID(of),
1360	    LOCKING_ANDX_OPLOCK_RELEASE);
1361
1362	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
1363	switch (session->s_state) {
1364	case SMB_SESSION_STATE_NEGOTIATED:
1365	case SMB_SESSION_STATE_OPLOCK_BREAKING:
1366		session->s_state = SMB_SESSION_STATE_OPLOCK_BREAKING;
1367		(void) smb_session_send(session, 0, mbc);
1368		smb_mbc_free(mbc);
1369		break;
1370
1371	case SMB_SESSION_STATE_READ_RAW_ACTIVE:
1372		list_insert_tail(&session->s_oplock_brkreqs, mbc);
1373		break;
1374
1375	case SMB_SESSION_STATE_DISCONNECTED:
1376	case SMB_SESSION_STATE_TERMINATED:
1377		smb_mbc_free(mbc);
1378		break;
1379
1380	default:
1381		SMB_PANIC();
1382	}
1383	smb_rwx_rwexit(&session->s_lock);
1384}
1385