xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_session.c (revision faa1795a28a5c712eed6d0a3f84d98c368a316c6)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/atomic.h>
29 #include <sys/strsubr.h>
30 #include <sys/synch.h>
31 #include <sys/types.h>
32 #include <sys/socketvar.h>
33 #include <sys/sdt.h>
34 #include <smbsrv/netbios.h>
35 #include <smbsrv/smb_incl.h>
36 #include <smbsrv/smb_i18n.h>
37 
38 static volatile uint64_t smb_kids;
39 
40 uint32_t smb_keep_alive = SSN_KEEP_ALIVE_TIMEOUT;
41 
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 
46 static void smb_request_init_command_mbuf(smb_request_t *sr);
47 
48 
49 void
50 smb_session_timers(smb_session_list_t *se)
51 {
52 	smb_session_t	*session;
53 
54 	rw_enter(&se->se_lock, RW_READER);
55 	session = list_head(&se->se_act.lst);
56 	while (session) {
57 		/*
58 		 * Walk through the table and decrement each keep_alive
59 		 * timer that has not timed out yet. (keepalive > 0)
60 		 */
61 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
62 		if (session->keep_alive &&
63 		    (session->keep_alive != (uint32_t)-1))
64 			session->keep_alive--;
65 		session = list_next(&se->se_act.lst, session);
66 	}
67 	rw_exit(&se->se_lock);
68 }
69 
70 void
71 smb_session_correct_keep_alive_values(
72     smb_session_list_t	*se,
73     uint32_t		new_keep_alive)
74 {
75 	smb_session_t		*sn;
76 
77 	if (new_keep_alive == smb_keep_alive)
78 		return;
79 	/*
80 	 * keep alive == 0 means do not drop connection if it's idle
81 	 */
82 	smb_keep_alive = (new_keep_alive) ? new_keep_alive : -1;
83 
84 	/*
85 	 * Walk through the table and set each session to the new keep_alive
86 	 * value if they have not already timed out.  Block clock interrupts.
87 	 */
88 	rw_enter(&se->se_lock, RW_READER);
89 	sn = list_head(&se->se_rdy.lst);
90 	while (sn) {
91 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
92 		sn->keep_alive = new_keep_alive;
93 		sn = list_next(&se->se_rdy.lst, sn);
94 	}
95 	sn = list_head(&se->se_act.lst);
96 	while (sn) {
97 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
98 		if (sn->keep_alive)
99 			sn->keep_alive = new_keep_alive;
100 		sn = list_next(&se->se_act.lst, sn);
101 	}
102 	rw_exit(&se->se_lock);
103 }
104 
105 /*
106  * smb_reconnection_check
107  *
108  * This function is called when a client indicates its current connection
109  * should be the only one it has with the server, as indicated by VC=0 in
110  * a SessionSetupX request. We go through the session list and destroy any
111  * stale connections for that client.
112  *
113  * Clients don't associate IP addresses and servers. So a client may make
114  * independent connections (i.e. with VC=0) to a server with multiple
115  * IP addresses. So, when checking for a reconnection, we need to include
116  * the local IP address, to which the client is connecting, when checking
117  * for stale sessions.
118  *
119  * Also check the server's NetBIOS name to support simultaneous access by
120  * multiple clients behind a NAT server.  This will only work for SMB over
121  * NetBIOS on TCP port 139, it will not work SMB over TCP port 445 because
122  * there is no NetBIOS name.  See also Knowledge Base article Q301673.
123  */
124 void
125 smb_session_reconnection_check(smb_session_list_t *se, smb_session_t *session)
126 {
127 	smb_session_t	*sn;
128 
129 	rw_enter(&se->se_lock, RW_READER);
130 	sn = list_head(&se->se_act.lst);
131 	while (sn) {
132 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
133 		if ((sn != session) &&
134 		    (sn->ipaddr == session->ipaddr) &&
135 		    (sn->local_ipaddr == session->local_ipaddr) &&
136 		    (strcasecmp(sn->workstation, session->workstation) == 0) &&
137 		    (sn->opentime <= session->opentime) &&
138 		    (sn->s_kid < session->s_kid)) {
139 			tsignal(sn->s_thread, SIGINT);
140 		}
141 		sn = list_next(&se->se_act.lst, sn);
142 	}
143 	rw_exit(&se->se_lock);
144 }
145 
146 /*
147  * Send a session message - supports SMB-over-NBT and SMB-over-TCP.
148  *
149  * The mbuf chain is copied into a contiguous buffer so that the whole
150  * message is submitted to smb_sosend as a single request.  This should
151  * help Ethereal/Wireshark delineate the packets correctly even though
152  * TCP_NODELAY has been set on the socket.
153  *
154  * If an mbuf chain is provided, it will be freed and set to NULL here.
155  */
156 int
157 smb_session_send(smb_session_t *session, uint8_t type, struct mbuf_chain *mbc)
158 {
159 	struct mbuf	*m = NULL;
160 	smb_txbuf_t	*txb;
161 	int		len = 0;
162 	smb_xprt_t	hdr;
163 	int		rc;
164 	uint8_t		*data;
165 
166 	switch (session->s_state) {
167 	case SMB_SESSION_STATE_DISCONNECTED:
168 	case SMB_SESSION_STATE_TERMINATED:
169 		if ((mbc != NULL) && (mbc->chain != NULL)) {
170 			m_freem(mbc->chain);
171 			mbc->chain = NULL;
172 			mbc->flags = 0;
173 		}
174 		return (ENOTCONN);
175 	default:
176 		break;
177 	}
178 
179 	txb = smb_net_txb_alloc();
180 
181 	if ((mbc != NULL) && (mbc->chain != NULL)) {
182 		len = NETBIOS_HDR_SZ;	/* Account for the NBT header. */
183 		m = mbc->chain;
184 		data = &txb->tb_data[len];
185 
186 		while (m) {
187 			if ((len + m->m_len) > sizeof (txb->tb_data)) {
188 				smb_net_txb_free(txb);
189 				m_freem(mbc->chain);
190 				mbc->chain = NULL;
191 				mbc->flags = 0;
192 				return (EMSGSIZE);
193 			}
194 			bcopy(m->m_data, data, m->m_len);
195 			data += m->m_len;
196 			len += m->m_len;
197 			m = m->m_next;
198 		}
199 
200 		m_freem(mbc->chain);
201 		mbc->chain = NULL;
202 		mbc->flags = 0;
203 		len -= NETBIOS_HDR_SZ;
204 	}
205 
206 	hdr.xh_type = type;
207 	hdr.xh_length = len;
208 
209 	rc = smb_session_xprt_puthdr(session, &hdr, txb->tb_data,
210 	    NETBIOS_HDR_SZ);
211 	if (rc == 0) {
212 		txb->tb_len = len + NETBIOS_HDR_SZ;
213 		rc = smb_net_txb_send(session->sock, &session->s_txlst, txb);
214 	} else {
215 		smb_net_txb_free(txb);
216 	}
217 	return (rc);
218 }
219 
220 /*
221  * Read, process and respond to a NetBIOS session request.
222  *
223  * A NetBIOS session must be established for SMB-over-NetBIOS.  Validate
224  * the calling and called name format and save the client NetBIOS name,
225  * which is used when a NetBIOS session is established to check for and
226  * cleanup leftover state from a previous session.
227  *
228  * Session requests are not valid for SMB-over-TCP, which is unfortunate
229  * because without the client name leftover state cannot be cleaned up
230  * if the client is behind a NAT server.
231  */
232 static int
233 smb_session_request(struct smb_session *session)
234 {
235 	int			rc;
236 	char			*calling_name;
237 	char			*called_name;
238 	char 			client_name[NETBIOS_NAME_SZ];
239 	struct mbuf_chain 	mbc;
240 	char 			*names = NULL;
241 	mts_wchar_t		*wbuf = NULL;
242 	smb_xprt_t		hdr;
243 	char *p;
244 	unsigned int cpid = oem_get_smb_cpid();
245 	int rc1, rc2;
246 
247 	session->keep_alive = smb_keep_alive;
248 
249 	if ((rc = smb_session_xprt_gethdr(session, &hdr)) != 0)
250 		return (rc);
251 
252 	DTRACE_PROBE2(receive__session__req__xprthdr, struct session *, session,
253 	    smb_xprt_t *, &hdr);
254 
255 	if ((hdr.xh_type != SESSION_REQUEST) ||
256 	    (hdr.xh_length != NETBIOS_SESSION_REQUEST_DATA_LENGTH)) {
257 		DTRACE_PROBE1(receive__session__req__failed,
258 		    struct session *, session);
259 		return (EINVAL);
260 	}
261 
262 	names = kmem_alloc(hdr.xh_length, KM_SLEEP);
263 
264 	if ((rc = smb_sorecv(session->sock, names, hdr.xh_length)) != 0) {
265 		kmem_free(names, hdr.xh_length);
266 		DTRACE_PROBE1(receive__session__req__failed,
267 		    struct session *, session);
268 		return (rc);
269 	}
270 
271 	DTRACE_PROBE3(receive__session__req__data, struct session *, session,
272 	    char *, names, uint32_t, hdr.xh_length);
273 
274 	called_name = &names[0];
275 	calling_name = &names[NETBIOS_ENCODED_NAME_SZ + 2];
276 
277 	rc1 = netbios_name_isvalid(called_name, 0);
278 	rc2 = netbios_name_isvalid(calling_name, client_name);
279 
280 	if (rc1 == 0 || rc2 == 0) {
281 
282 		DTRACE_PROBE3(receive__invalid__session__req,
283 		    struct session *, session, char *, names,
284 		    uint32_t, hdr.xh_length);
285 
286 		kmem_free(names, hdr.xh_length);
287 		MBC_INIT(&mbc, MAX_DATAGRAM_LENGTH);
288 		(void) smb_encode_mbc(&mbc, "b",
289 		    DATAGRAM_INVALID_SOURCE_NAME_FORMAT);
290 		(void) smb_session_send(session, NEGATIVE_SESSION_RESPONSE,
291 		    &mbc);
292 		return (EINVAL);
293 	}
294 
295 	DTRACE_PROBE3(receive__session__req__calling__decoded,
296 	    struct session *, session,
297 	    char *, calling_name, char *, client_name);
298 
299 	/*
300 	 * The client NetBIOS name is in oem codepage format.
301 	 * We need to convert it to unicode and store it in
302 	 * multi-byte format.  We also need to strip off any
303 	 * spaces added as part of the NetBIOS name encoding.
304 	 */
305 	wbuf = kmem_alloc((SMB_PI_MAX_HOST * sizeof (mts_wchar_t)), KM_SLEEP);
306 	(void) oemstounicodes(wbuf, client_name, SMB_PI_MAX_HOST, cpid);
307 	(void) mts_wcstombs(session->workstation, wbuf, SMB_PI_MAX_HOST);
308 	kmem_free(wbuf, (SMB_PI_MAX_HOST * sizeof (mts_wchar_t)));
309 
310 	if ((p = strchr(session->workstation, ' ')) != 0)
311 		*p = '\0';
312 
313 	kmem_free(names, hdr.xh_length);
314 	return (smb_session_send(session, POSITIVE_SESSION_RESPONSE, NULL));
315 }
316 
317 /*
318  * Read 4-byte header from the session socket and build an in-memory
319  * session transport header.  See smb_xprt_t definition for header
320  * format information.
321  *
322  * Direct hosted NetBIOS-less SMB (SMB-over-TCP) uses port 445.  The
323  * first byte of the four-byte header must be 0 and the next three
324  * bytes contain the length of the remaining data.
325  */
326 int
327 smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr)
328 {
329 	int		rc;
330 	unsigned char	buf[NETBIOS_HDR_SZ];
331 
332 	if ((rc = smb_sorecv(session->sock, buf, NETBIOS_HDR_SZ)) != 0)
333 		return (rc);
334 
335 	switch (session->s_local_port) {
336 	case SSN_SRVC_TCP_PORT:
337 		ret_hdr->xh_type = buf[0];
338 		ret_hdr->xh_length = (((uint32_t)buf[1] & 1) << 16) |
339 		    ((uint32_t)buf[2] << 8) |
340 		    ((uint32_t)buf[3]);
341 		break;
342 
343 	case SMB_SRVC_TCP_PORT:
344 		ret_hdr->xh_type = buf[0];
345 
346 		if (ret_hdr->xh_type != 0) {
347 			cmn_err(CE_WARN, "0x%08x: invalid type (%u)",
348 			    session->ipaddr, ret_hdr->xh_type);
349 			return (EPROTO);
350 		}
351 
352 		ret_hdr->xh_length = ((uint32_t)buf[1] << 16) |
353 		    ((uint32_t)buf[2] << 8) |
354 		    ((uint32_t)buf[3]);
355 		break;
356 
357 	default:
358 		cmn_err(CE_WARN, "0x%08x: invalid port %u",
359 		    session->ipaddr, session->s_local_port);
360 		return (EPROTO);
361 	}
362 
363 	return (0);
364 }
365 
366 /*
367  * Encode a transport session packet header into a 4-byte buffer.
368  * See smb_xprt_t definition for header format information.
369  */
370 static int
371 smb_session_xprt_puthdr(smb_session_t *session, smb_xprt_t *hdr,
372     uint8_t *buf, size_t buflen)
373 {
374 	if (session == NULL || hdr == NULL ||
375 	    buf == NULL || buflen < NETBIOS_HDR_SZ) {
376 		return (-1);
377 	}
378 
379 	switch (session->s_local_port) {
380 	case SSN_SRVC_TCP_PORT:
381 		buf[0] = hdr->xh_type;
382 		buf[1] = ((hdr->xh_length >> 16) & 1);
383 		buf[2] = (hdr->xh_length >> 8) & 0xff;
384 		buf[3] = hdr->xh_length & 0xff;
385 		break;
386 
387 	case SMB_SRVC_TCP_PORT:
388 		buf[0] = hdr->xh_type;
389 		buf[1] = (hdr->xh_length >> 16) & 0xff;
390 		buf[2] = (hdr->xh_length >> 8) & 0xff;
391 		buf[3] = hdr->xh_length & 0xff;
392 		break;
393 
394 	default:
395 		cmn_err(CE_WARN, "0x%08x: invalid port (%u)",
396 		    session->ipaddr, session->s_local_port);
397 		return (-1);
398 	}
399 
400 	return (0);
401 }
402 
403 static void
404 smb_request_init_command_mbuf(smb_request_t *sr)
405 {
406 	MGET(sr->command.chain, 0, MT_DATA);
407 
408 	/*
409 	 * Setup mbuf, mimic MCLGET but use the complete packet buffer.
410 	 */
411 	sr->command.chain->m_ext.ext_buf = sr->sr_request_buf;
412 	sr->command.chain->m_data = sr->command.chain->m_ext.ext_buf;
413 	sr->command.chain->m_len = sr->sr_req_length;
414 	sr->command.chain->m_flags |= M_EXT;
415 	sr->command.chain->m_ext.ext_size = sr->sr_req_length;
416 	sr->command.chain->m_ext.ext_ref = &mclrefnoop;
417 
418 	/*
419 	 * Initialize the rest of the mbuf_chain fields
420 	 */
421 	sr->command.flags = 0;
422 	sr->command.shadow_of = 0;
423 	sr->command.max_bytes = sr->sr_req_length;
424 	sr->command.chain_offset = 0;
425 }
426 
427 /*
428  * smb_request_cancel
429  *
430  * Handle a cancel for a request properly depending on the current request
431  * state.
432  */
433 void
434 smb_request_cancel(smb_request_t *sr)
435 {
436 	mutex_enter(&sr->sr_mutex);
437 	switch (sr->sr_state) {
438 
439 	case SMB_REQ_STATE_SUBMITTED:
440 	case SMB_REQ_STATE_ACTIVE:
441 	case SMB_REQ_STATE_CLEANED_UP:
442 		sr->sr_state = SMB_REQ_STATE_CANCELED;
443 		break;
444 
445 	case SMB_REQ_STATE_WAITING_LOCK:
446 		/*
447 		 * This request is waiting on a lock.  Wakeup everything
448 		 * waiting on the lock so that the relevant thread regains
449 		 * control and notices that is has been canceled.  The
450 		 * other lock request threads waiting on this lock will go
451 		 * back to sleep when they discover they are still blocked.
452 		 */
453 		sr->sr_state = SMB_REQ_STATE_CANCELED;
454 
455 		ASSERT(sr->sr_awaiting != NULL);
456 		mutex_enter(&sr->sr_awaiting->l_mutex);
457 		cv_broadcast(&sr->sr_awaiting->l_cv);
458 		mutex_exit(&sr->sr_awaiting->l_mutex);
459 
460 		break;
461 
462 	case SMB_REQ_STATE_WAITING_EVENT:
463 	case SMB_REQ_STATE_EVENT_OCCURRED:
464 		/*
465 		 * Cancellations for these states are handled by the
466 		 * notify-change code
467 		 */
468 		break;
469 
470 	case SMB_REQ_STATE_COMPLETED:
471 	case SMB_REQ_STATE_CANCELED:
472 		/*
473 		 * No action required for these states since the request
474 		 * is completing.
475 		 */
476 		break;
477 	/*
478 	 * Cases included:
479 	 *	SMB_REQ_STATE_FREE:
480 	 *	SMB_REQ_STATE_INITIALIZING:
481 	 */
482 	default:
483 		ASSERT(0);
484 		break;
485 	}
486 	mutex_exit(&sr->sr_mutex);
487 }
488 
489 /*
490  * This is the entry point for processing SMB messages over NetBIOS or
491  * SMB-over-TCP.
492  *
493  * NetBIOS connections require a session request to establish a session
494  * on which to send session messages.
495  *
496  * Session requests are not valid on SMB-over-TCP.  We don't need to do
497  * anything here as session requests will be treated as an error when
498  * handling session messages.
499  */
500 int
501 smb_session_daemon(smb_session_list_t *se)
502 {
503 	int		rc = 0;
504 	smb_session_t	*session;
505 
506 	session = smb_session_list_activate_head(se);
507 	if (session == NULL)
508 		return (EINVAL);
509 
510 	if (session->s_local_port == SSN_SRVC_TCP_PORT) {
511 		rc = smb_session_request(session);
512 		if (rc) {
513 			smb_rwx_rwenter(&session->s_lock, RW_WRITER);
514 			session->s_state = SMB_SESSION_STATE_DISCONNECTED;
515 			smb_rwx_rwexit(&session->s_lock);
516 			smb_session_list_terminate(se, session);
517 			return (rc);
518 		}
519 	}
520 
521 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
522 	session->s_state = SMB_SESSION_STATE_ESTABLISHED;
523 	smb_rwx_rwexit(&session->s_lock);
524 
525 	rc = smb_session_message(session);
526 
527 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
528 	session->s_state = SMB_SESSION_STATE_DISCONNECTED;
529 	smb_rwx_rwexit(&session->s_lock);
530 
531 	smb_soshutdown(session->sock);
532 
533 	DTRACE_PROBE2(session__drop, struct session *, session, int, rc);
534 
535 	smb_session_cancel(session);
536 
537 	/*
538 	 * At this point everything related to the session should have been
539 	 * cleaned up and we expect that nothing will attempt to use the
540 	 * socket.
541 	 */
542 	smb_session_list_terminate(se, session);
543 
544 	return (rc);
545 }
546 
547 /*
548  * Read and process SMB requests.
549  *
550  * Returns:
551  *	0	Success
552  *	1	Unable to read transport header
553  *	2	Invalid transport header type
554  *	3	Invalid SMB length (too small)
555  *	4	Unable to read SMB header
556  *	5	Invalid SMB header (bad magic number)
557  *	6	Unable to read SMB data
558  *	2x	Write raw failed
559  */
560 static int
561 smb_session_message(smb_session_t *session)
562 {
563 	smb_request_t	*sr = NULL;
564 	smb_xprt_t	hdr;
565 	uint8_t		*req_buf;
566 	uint32_t	resid;
567 	int		rc;
568 
569 	for (;;) {
570 
571 		rc = smb_session_xprt_gethdr(session, &hdr);
572 		if (rc)
573 			return (rc);
574 
575 		DTRACE_PROBE2(session__receive__xprthdr, session_t *, session,
576 		    smb_xprt_t *, &hdr);
577 
578 		if (hdr.xh_type != SESSION_MESSAGE) {
579 			/*
580 			 * Anything other than SESSION_MESSAGE or
581 			 * SESSION_KEEP_ALIVE is an error.  A SESSION_REQUEST
582 			 * may indicate a new session request but we need to
583 			 * close this session and we can treat it as an error
584 			 * here.
585 			 */
586 			if (hdr.xh_type == SESSION_KEEP_ALIVE) {
587 				session->keep_alive = smb_keep_alive;
588 				continue;
589 			}
590 			return (EPROTO);
591 		}
592 
593 		if (hdr.xh_length < SMB_HEADER_LEN)
594 			return (EPROTO);
595 
596 		session->keep_alive = smb_keep_alive;
597 
598 		/*
599 		 * Allocate a request context, read the SMB header and validate
600 		 * it. The sr includes a buffer large enough to hold the SMB
601 		 * request payload.  If the header looks valid, read any
602 		 * remaining data.
603 		 */
604 		sr = smb_request_alloc(session, hdr.xh_length);
605 
606 		req_buf = (uint8_t *)sr->sr_request_buf;
607 		resid = hdr.xh_length;
608 
609 		rc = smb_sorecv(session->sock, req_buf, SMB_HEADER_LEN);
610 		if (rc) {
611 			smb_request_free(sr);
612 			return (rc);
613 		}
614 
615 		if (SMB_PROTOCOL_MAGIC_INVALID(sr)) {
616 			smb_request_free(sr);
617 			return (EPROTO);
618 		}
619 
620 		if (resid > SMB_HEADER_LEN) {
621 			req_buf += SMB_HEADER_LEN;
622 			resid -= SMB_HEADER_LEN;
623 
624 			rc = smb_sorecv(session->sock, req_buf, resid);
625 			if (rc) {
626 				smb_request_free(sr);
627 				return (rc);
628 			}
629 		}
630 
631 		/*
632 		 * Initialize command MBC to represent the received data.
633 		 */
634 		smb_request_init_command_mbuf(sr);
635 
636 		DTRACE_PROBE1(session__receive__smb, smb_request_t *, sr);
637 
638 		/*
639 		 * If this is a raw write, hand off the request.  The handler
640 		 * will retrieve the remaining raw data and process the request.
641 		 */
642 		if (SMB_IS_WRITERAW(sr)) {
643 			rc = smb_handle_write_raw(session, sr);
644 			/* XXX smb_request_free(sr); ??? */
645 			return (rc);
646 		}
647 
648 		sr->sr_state = SMB_REQ_STATE_SUBMITTED;
649 		(void) taskq_dispatch(session->s_server->sv_thread_pool,
650 		    smb_session_worker, sr, TQ_SLEEP);
651 	}
652 }
653 
654 /*
655  * smb_session_reject
656  *
657  * Build and send a NEGATIVE_SESSION_RESPONSE on the specified socket.
658  * The reason is written to the log.
659  */
660 /*ARGSUSED*/
661 void
662 smb_session_reject(smb_session_t *session, char *reason)
663 {
664 	smb_txbuf_t	*txb;
665 
666 	smb_rwx_rwenter(&session->s_lock, RW_READER);
667 	if (session->sock != NULL) {
668 		txb = smb_net_txb_alloc();
669 		txb->tb_data[0] = NEGATIVE_SESSION_RESPONSE;
670 		txb->tb_data[1] = 0;
671 		txb->tb_data[2] = 0;
672 		txb->tb_data[3] = 1;
673 		txb->tb_data[4] = SESSION_INSUFFICIENT_RESOURCES;
674 		txb->tb_len = 5;
675 		(void) smb_net_txb_send(session->sock, &session->s_txlst, txb);
676 	}
677 	smb_rwx_rwexit(&session->s_lock);
678 }
679 
680 /*
681  * Port will be SSN_SRVC_TCP_PORT or SMB_SRVC_TCP_PORT.
682  */
683 smb_session_t *
684 smb_session_create(struct sonode *new_so, uint16_t port, smb_server_t *sv)
685 {
686 	uint32_t		ipaddr;
687 	uint32_t		local_ipaddr;
688 	struct sockaddr_in	sin;
689 	smb_session_t		*session;
690 
691 	session = kmem_cache_alloc(sv->si_cache_session, KM_SLEEP);
692 	bzero(session, sizeof (smb_session_t));
693 
694 	if (smb_idpool_constructor(&session->s_uid_pool)) {
695 		kmem_cache_free(sv->si_cache_session, session);
696 		return (NULL);
697 	}
698 
699 	session->s_kid = SMB_NEW_KID();
700 	session->s_state = SMB_SESSION_STATE_INITIALIZED;
701 	session->native_os = NATIVE_OS_UNKNOWN;
702 	session->opentime = lbolt64;
703 	session->keep_alive = smb_keep_alive;
704 	session->activity_timestamp = lbolt64;
705 
706 	smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t),
707 	    offsetof(smb_request_t, sr_session_lnd));
708 
709 	smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t),
710 	    offsetof(smb_user_t, u_lnd));
711 
712 	smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t),
713 	    offsetof(smb_xa_t, xa_lnd));
714 
715 	smb_net_txl_constructor(&session->s_txlst);
716 
717 	smb_rwx_init(&session->s_lock);
718 
719 	if (new_so) {
720 		bcopy(new_so->so_faddr_sa, &sin, new_so->so_faddr_len);
721 		ipaddr = sin.sin_addr.s_addr;
722 		bcopy(new_so->so_laddr_sa, &sin, new_so->so_faddr_len);
723 		local_ipaddr = sin.sin_addr.s_addr;
724 		session->s_local_port = port;
725 		session->ipaddr = ipaddr;
726 		session->local_ipaddr = local_ipaddr;
727 		session->sock = new_so;
728 	}
729 
730 	session->s_server = sv;
731 	smb_server_get_cfg(sv, &session->s_cfg);
732 	session->s_cache_request = sv->si_cache_request;
733 	session->s_cache = sv->si_cache_session;
734 	session->s_magic = SMB_SESSION_MAGIC;
735 	return (session);
736 }
737 
738 void
739 smb_session_delete(smb_session_t *session)
740 {
741 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
742 
743 	session->s_magic = (uint32_t)~SMB_SESSION_MAGIC;
744 
745 	smb_rwx_destroy(&session->s_lock);
746 	smb_net_txl_destructor(&session->s_txlst);
747 	smb_slist_destructor(&session->s_req_list);
748 	smb_llist_destructor(&session->s_user_list);
749 	smb_llist_destructor(&session->s_xa_list);
750 
751 	ASSERT(session->s_tree_cnt == 0);
752 	ASSERT(session->s_file_cnt == 0);
753 	ASSERT(session->s_dir_cnt == 0);
754 
755 	smb_idpool_destructor(&session->s_uid_pool);
756 	kmem_cache_free(session->s_cache, session);
757 }
758 
759 void
760 smb_session_cancel(smb_session_t *session)
761 {
762 	smb_xa_t	*xa, *nextxa;
763 
764 	/* All the request currently being treated must be canceled. */
765 	smb_session_cancel_requests(session);
766 
767 	/*
768 	 * We wait for the completion of all the requests associated with
769 	 * this session.
770 	 */
771 	smb_slist_wait_for_empty(&session->s_req_list);
772 
773 	/*
774 	 * At this point the reference count of the users, trees, files,
775 	 * directories should be zero. It should be possible to destroy them
776 	 * without any problem.
777 	 */
778 	xa = smb_llist_head(&session->s_xa_list);
779 	while (xa) {
780 		nextxa = smb_llist_next(&session->s_xa_list, xa);
781 		smb_xa_close(xa);
782 		xa = nextxa;
783 	}
784 	smb_user_logoff_all(session);
785 }
786 
787 void
788 smb_session_cancel_requests(
789     smb_session_t	*session)
790 {
791 	smb_request_t	*sr;
792 	smb_request_t	*tmp;
793 
794 	/* All the SMB requests on the notification queue are canceled. */
795 	smb_process_session_notify_change_queue(session);
796 
797 	smb_slist_enter(&session->s_req_list);
798 	sr = smb_slist_head(&session->s_req_list);
799 	while (sr) {
800 		ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
801 		tmp = smb_slist_next(&session->s_req_list, sr);
802 
803 		smb_request_cancel(sr);
804 
805 		sr = tmp;
806 	}
807 	smb_slist_exit(&session->s_req_list);
808 }
809 
810 void
811 smb_session_worker(
812     void	*arg)
813 {
814 	smb_request_t	*sr;
815 
816 	sr = (smb_request_t *)arg;
817 
818 	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
819 
820 
821 	mutex_enter(&sr->sr_mutex);
822 	switch (sr->sr_state) {
823 	case SMB_REQ_STATE_SUBMITTED:
824 		mutex_exit(&sr->sr_mutex);
825 		smb_dispatch_request(sr);
826 		mutex_enter(&sr->sr_mutex);
827 		if (!sr->sr_keep) {
828 			sr->sr_state = SMB_REQ_STATE_COMPLETED;
829 			mutex_exit(&sr->sr_mutex);
830 			smb_request_free(sr);
831 			break;
832 		}
833 		mutex_exit(&sr->sr_mutex);
834 		break;
835 
836 	default:
837 		ASSERT(sr->sr_state == SMB_REQ_STATE_CANCELED);
838 		sr->sr_state = SMB_REQ_STATE_COMPLETED;
839 		mutex_exit(&sr->sr_mutex);
840 		smb_request_free(sr);
841 		break;
842 	}
843 }
844 
845 /*
846  * smb_session_disconnect_share
847  *
848  * Disconnects the specified share. This function should be called after the
849  * share passed in has been made unavailable by the "share manager".
850  */
851 void
852 smb_session_disconnect_share(smb_session_list_t *se, char *sharename)
853 {
854 	smb_session_t	*session;
855 
856 	rw_enter(&se->se_lock, RW_READER);
857 	session = list_head(&se->se_act.lst);
858 	while (session) {
859 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
860 		smb_rwx_rwenter(&session->s_lock, RW_READER);
861 		switch (session->s_state) {
862 		case SMB_SESSION_STATE_NEGOTIATED:
863 		case SMB_SESSION_STATE_OPLOCK_BREAKING:
864 		case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: {
865 			smb_user_t	*user;
866 			smb_user_t	*next;
867 
868 			user = smb_user_lookup_by_state(session, NULL);
869 			while (user) {
870 				smb_user_disconnect_share(user, sharename);
871 				next = smb_user_lookup_by_state(session, user);
872 				smb_user_release(user);
873 				user = next;
874 			}
875 			break;
876 
877 		}
878 		default:
879 			break;
880 		}
881 		smb_rwx_rwexit(&session->s_lock);
882 		session = list_next(&se->se_act.lst, session);
883 	}
884 	rw_exit(&se->se_lock);
885 }
886 
887 /*
888  * smb_session_disconnect_volume
889  *
890  * This function is called when a volume is deleted. We need to ensure
891  * all trees with a reference to the volume are destroyed before we
892  * discard the fs_online. Before destroying each tree, we notify any
893  * in-progress requests and give them a chance to complete.
894  *
895  * NOTE:
896  * We shouldn't be accepting any new connection on this volume while
897  * we are in this function.
898  */
899 void
900 smb_session_disconnect_volume(smb_session_list_t *se, fs_desc_t *fsd)
901 {
902 	smb_session_t	*session;
903 
904 	rw_enter(&se->se_lock, RW_READER);
905 	session = list_head(&se->se_act.lst);
906 	while (session) {
907 
908 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
909 		smb_rwx_rwenter(&session->s_lock, RW_READER);
910 		switch (session->s_state) {
911 		case SMB_SESSION_STATE_NEGOTIATED:
912 		case SMB_SESSION_STATE_OPLOCK_BREAKING:
913 		case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: {
914 			smb_user_t	*user;
915 			smb_user_t	*next;
916 
917 			user = smb_user_lookup_by_state(session, NULL);
918 			while (user) {
919 				smb_user_disconnect_volume(user, fsd);
920 				next = smb_user_lookup_by_state(session, user);
921 				smb_user_release(user);
922 				user = next;
923 			}
924 			break;
925 
926 		}
927 		default:
928 			break;
929 		}
930 		smb_rwx_rwexit(&session->s_lock);
931 		session = list_next(&se->se_act.lst, session);
932 	}
933 	rw_exit(&se->se_lock);
934 }
935 
936 void
937 smb_session_list_constructor(smb_session_list_t *se)
938 {
939 	bzero(se, sizeof (*se));
940 	rw_init(&se->se_lock, NULL, RW_DEFAULT, NULL);
941 	list_create(&se->se_rdy.lst, sizeof (smb_session_t),
942 	    offsetof(smb_session_t, s_lnd));
943 	list_create(&se->se_act.lst, sizeof (smb_session_t),
944 	    offsetof(smb_session_t, s_lnd));
945 }
946 
947 void
948 smb_session_list_destructor(smb_session_list_t *se)
949 {
950 	list_destroy(&se->se_rdy.lst);
951 	list_destroy(&se->se_act.lst);
952 	rw_destroy(&se->se_lock);
953 }
954 
955 void
956 smb_session_list_append(smb_session_list_t *se, smb_session_t *session)
957 {
958 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
959 	ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
960 
961 	rw_enter(&se->se_lock, RW_WRITER);
962 	list_insert_tail(&se->se_rdy.lst, session);
963 	se->se_rdy.count++;
964 	se->se_wrop++;
965 	rw_exit(&se->se_lock);
966 }
967 
968 void
969 smb_session_list_delete_tail(smb_session_list_t *se)
970 {
971 	smb_session_t	*session;
972 
973 	rw_enter(&se->se_lock, RW_WRITER);
974 	session = list_tail(&se->se_rdy.lst);
975 	if (session) {
976 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
977 		ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
978 		list_remove(&se->se_rdy.lst, session);
979 		ASSERT(se->se_rdy.count);
980 		se->se_rdy.count--;
981 		rw_exit(&se->se_lock);
982 		smb_session_delete(session);
983 		return;
984 	}
985 	rw_exit(&se->se_lock);
986 }
987 
988 smb_session_t *
989 smb_session_list_activate_head(smb_session_list_t *se)
990 {
991 	smb_session_t	*session;
992 
993 	rw_enter(&se->se_lock, RW_WRITER);
994 	session = list_head(&se->se_rdy.lst);
995 	if (session) {
996 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
997 		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
998 		ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
999 		session->s_thread = curthread;
1000 		session->s_ktdid = session->s_thread->t_did;
1001 		smb_rwx_rwexit(&session->s_lock);
1002 		list_remove(&se->se_rdy.lst, session);
1003 		se->se_rdy.count--;
1004 		list_insert_tail(&se->se_act.lst, session);
1005 		se->se_act.count++;
1006 		se->se_wrop++;
1007 	}
1008 	rw_exit(&se->se_lock);
1009 	return (session);
1010 }
1011 
1012 void
1013 smb_session_list_terminate(smb_session_list_t *se, smb_session_t *session)
1014 {
1015 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1016 
1017 	rw_enter(&se->se_lock, RW_WRITER);
1018 
1019 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
1020 	ASSERT(session->s_state == SMB_SESSION_STATE_DISCONNECTED);
1021 	session->s_state = SMB_SESSION_STATE_TERMINATED;
1022 	smb_sodestroy(session->sock);
1023 	session->sock = NULL;
1024 	smb_rwx_rwexit(&session->s_lock);
1025 
1026 	list_remove(&se->se_act.lst, session);
1027 	se->se_act.count--;
1028 	se->se_wrop++;
1029 
1030 	ASSERT(session->s_thread == curthread);
1031 
1032 	rw_exit(&se->se_lock);
1033 
1034 	smb_session_delete(session);
1035 }
1036 
1037 /*
1038  * smb_session_list_signal
1039  *
1040  * This function signals all the session threads. The intent is to terminate
1041  * them. The sessions still in the SMB_SESSION_STATE_INITIALIZED are delete
1042  * immediately.
1043  *
1044  * This function must only be called by the threads listening and accepting
1045  * connections. They must pass in their respective session list.
1046  */
1047 void
1048 smb_session_list_signal(smb_session_list_t *se)
1049 {
1050 	smb_session_t	*session;
1051 
1052 	rw_enter(&se->se_lock, RW_WRITER);
1053 	while (session = list_head(&se->se_rdy.lst)) {
1054 
1055 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1056 
1057 		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
1058 		ASSERT(session->s_state == SMB_SESSION_STATE_INITIALIZED);
1059 		session->s_state = SMB_SESSION_STATE_TERMINATED;
1060 		smb_sodestroy(session->sock);
1061 		session->sock = NULL;
1062 		smb_rwx_rwexit(&session->s_lock);
1063 
1064 		list_remove(&se->se_rdy.lst, session);
1065 		se->se_rdy.count--;
1066 		se->se_wrop++;
1067 
1068 		rw_exit(&se->se_lock);
1069 		smb_session_delete(session);
1070 		rw_enter(&se->se_lock, RW_WRITER);
1071 	}
1072 	rw_downgrade(&se->se_lock);
1073 
1074 	session = list_head(&se->se_act.lst);
1075 	while (session) {
1076 
1077 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1078 		tsignal(session->s_thread, SIGINT);
1079 		session = list_next(&se->se_act.lst, session);
1080 	}
1081 	rw_exit(&se->se_lock);
1082 }
1083 
1084 /*
1085  * smb_request_alloc
1086  *
1087  * Allocate an smb_request_t structure from the kmem_cache.  Partially
1088  * initialize the found/new request.
1089  *
1090  * Returns pointer to a request
1091  */
1092 smb_request_t *
1093 smb_request_alloc(smb_session_t *session, int req_length)
1094 {
1095 	smb_request_t	*sr;
1096 
1097 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1098 
1099 	sr = kmem_cache_alloc(session->s_cache_request, KM_SLEEP);
1100 
1101 	/*
1102 	 * Future:  Use constructor to pre-initialize some fields.  For now
1103 	 * there are so many fields that it is easiest just to zero the
1104 	 * whole thing and start over.
1105 	 */
1106 	bzero(sr, sizeof (smb_request_t));
1107 
1108 	mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL);
1109 	sr->session = session;
1110 	sr->sr_server = session->s_server;
1111 	sr->sr_gmtoff = session->s_server->si_gmtoff;
1112 	sr->sr_cache = session->s_server->si_cache_request;
1113 	sr->sr_cfg = &session->s_cfg;
1114 	sr->request_storage.forw = &sr->request_storage;
1115 	sr->request_storage.back = &sr->request_storage;
1116 	sr->command.max_bytes = req_length;
1117 	sr->reply.max_bytes = smb_maxbufsize;
1118 	sr->sr_req_length = req_length;
1119 	if (req_length)
1120 		sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP);
1121 	sr->sr_magic = SMB_REQ_MAGIC;
1122 	sr->sr_state = SMB_REQ_STATE_INITIALIZING;
1123 	smb_slist_insert_tail(&session->s_req_list, sr);
1124 	return (sr);
1125 }
1126 
1127 /*
1128  * smb_request_free
1129  *
1130  * release the memories which have been allocated for a smb request.
1131  */
1132 void
1133 smb_request_free(smb_request_t *sr)
1134 {
1135 	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
1136 	ASSERT(sr->session);
1137 	ASSERT(sr->fid_ofile == NULL);
1138 	ASSERT(sr->sid_odir == NULL);
1139 	ASSERT(sr->r_xa == NULL);
1140 
1141 	if (sr->tid_tree)
1142 		smb_tree_release(sr->tid_tree);
1143 
1144 	if (sr->uid_user)
1145 		smb_user_release(sr->uid_user);
1146 
1147 	smb_slist_remove(&sr->session->s_req_list, sr);
1148 
1149 	sr->session = NULL;
1150 
1151 	/* Release any temp storage */
1152 	smbsr_free_malloc_list(&sr->request_storage);
1153 
1154 	if (sr->sr_request_buf)
1155 		kmem_free(sr->sr_request_buf, sr->sr_req_length);
1156 	if (sr->command.chain)
1157 		m_freem(sr->command.chain);
1158 	if (sr->reply.chain)
1159 		m_freem(sr->reply.chain);
1160 	if (sr->raw_data.chain)
1161 		m_freem(sr->raw_data.chain);
1162 
1163 	sr->sr_magic = 0;
1164 	mutex_destroy(&sr->sr_mutex);
1165 	kmem_cache_free(sr->sr_cache, sr);
1166 }
1167