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