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