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