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