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