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