1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 238d94f651SGordon Ross * Copyright 2019 Nexenta Systems, Inc. All rights reserved. 24da6c28aaSamw */ 25b819cea2SGordon Ross 26da6c28aaSamw #include <sys/atomic.h> 27da6c28aaSamw #include <sys/synch.h> 28da6c28aaSamw #include <sys/types.h> 29da6c28aaSamw #include <sys/sdt.h> 30f9bc6dadSDmitry.Savitsky@nexenta.com #include <sys/random.h> 31da6c28aaSamw #include <smbsrv/netbios.h> 32a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h> 33bbf6f00cSJordan Brown #include <smbsrv/string.h> 34b819cea2SGordon Ross #include <netinet/tcp.h> 35b819cea2SGordon Ross 36a90cf9f2SGordon Ross /* How many iovec we'll handle as a local array (no allocation) */ 37a90cf9f2SGordon Ross #define SMB_LOCAL_IOV_MAX 16 38a90cf9f2SGordon Ross 39b819cea2SGordon Ross #define SMB_NEW_KID() atomic_inc_64_nv(&smb_kids) 40da6c28aaSamw 41faa1795aSjb150015 static volatile uint64_t smb_kids; 42da6c28aaSamw 43b819cea2SGordon Ross /* 44b819cea2SGordon Ross * We track the keepalive in minutes, but this constant 45b819cea2SGordon Ross * specifies it in seconds, so convert to minutes. 46b819cea2SGordon Ross */ 47b819cea2SGordon Ross uint32_t smb_keep_alive = SMB_PI_KEEP_ALIVE_MIN / 60; 48da6c28aaSamw 490897f7fbSGordon Ross /* 50*817fa55fSGordon Ross * This is the maximum time we'll allow a "session" to exist with no 51*817fa55fSGordon Ross * authenticated smb_user_t objects on it. This allows a client to 52*817fa55fSGordon Ross * logoff their "one and only" user session and then logon as some 53*817fa55fSGordon Ross * different user. (There are some tests that do that.) The same 54*817fa55fSGordon Ross * timeout mechanism also reduces the impact of clients that might 55*817fa55fSGordon Ross * open TCP connections but never authenticate. 56*817fa55fSGordon Ross */ 57*817fa55fSGordon Ross int smb_session_auth_tmo = 30; /* sec. */ 58*817fa55fSGordon Ross 59*817fa55fSGordon Ross /* 600897f7fbSGordon Ross * There are many smbtorture test cases that send 610897f7fbSGordon Ross * racing requests, and where the tests fail if we 620897f7fbSGordon Ross * don't execute them in exactly the order sent. 630897f7fbSGordon Ross * These are test bugs. The protocol makes no 640897f7fbSGordon Ross * guarantees about execution order of requests 650897f7fbSGordon Ross * that are concurrently active. 660897f7fbSGordon Ross * 670897f7fbSGordon Ross * Nonetheless, smbtorture has many useful tests, 680897f7fbSGordon Ross * so we have this work-around we can enable to 690897f7fbSGordon Ross * basically force sequential execution. When 700897f7fbSGordon Ross * enabled, insert a delay after each request is 710897f7fbSGordon Ross * issued a taskq job. Enable this with mdb by 720897f7fbSGordon Ross * setting smb_reader_delay to 10. Don't make it 730897f7fbSGordon Ross * more than 500 or so or the server will appear 740897f7fbSGordon Ross * to be so slow that tests may time out. 750897f7fbSGordon Ross */ 760897f7fbSGordon Ross int smb_reader_delay = 0; /* mSec. */ 770897f7fbSGordon Ross 78a90cf9f2SGordon Ross static int smbsr_newrq_initial(smb_request_t *); 79a90cf9f2SGordon Ross 802c2961f8Sjose borrego static void smb_session_cancel(smb_session_t *); 81a90cf9f2SGordon Ross static int smb_session_reader(smb_session_t *); 82a90cf9f2SGordon Ross static int smb_session_xprt_puthdr(smb_session_t *, 83a90cf9f2SGordon Ross uint8_t msg_type, uint32_t msg_len, 84a90cf9f2SGordon Ross uint8_t *dst, size_t dstlen); 85811599a4SMatt Barden static void smb_session_disconnect_trees(smb_session_t *); 86faa1795aSjb150015 static void smb_request_init_command_mbuf(smb_request_t *sr); 87f9bc6dadSDmitry.Savitsky@nexenta.com static void smb_session_genkey(smb_session_t *); 88da6c28aaSamw 89811599a4SMatt Barden /* 90811599a4SMatt Barden * This (legacy) code is in support of an "idle timeout" feature, 91811599a4SMatt Barden * which is apparently incomplete. To complete it, we should: 92811599a4SMatt Barden * when the keep_alive timer expires, check whether the client 93811599a4SMatt Barden * has any open files, and if not then kill their session. 94811599a4SMatt Barden * Right now the timers are there, but nothing happens when 95811599a4SMatt Barden * a timer expires. 96811599a4SMatt Barden * 97811599a4SMatt Barden * Todo: complete logic to kill idle sessions. 98811599a4SMatt Barden * 99811599a4SMatt Barden * Only called when sv_cfg.skc_keepalive != 0 100811599a4SMatt Barden */ 101da6c28aaSamw void 102811599a4SMatt Barden smb_session_timers(smb_server_t *sv) 103da6c28aaSamw { 104faa1795aSjb150015 smb_session_t *session; 105811599a4SMatt Barden smb_llist_t *ll; 106da6c28aaSamw 107811599a4SMatt Barden ll = &sv->sv_session_list; 1084163af6aSjose borrego smb_llist_enter(ll, RW_READER); 1094163af6aSjose borrego session = smb_llist_head(ll); 1104163af6aSjose borrego while (session != NULL) { 111da6c28aaSamw /* 112da6c28aaSamw * Walk through the table and decrement each keep_alive 113da6c28aaSamw * timer that has not timed out yet. (keepalive > 0) 114da6c28aaSamw */ 1154163af6aSjose borrego SMB_SESSION_VALID(session); 116faa1795aSjb150015 if (session->keep_alive && 117faa1795aSjb150015 (session->keep_alive != (uint32_t)-1)) 118faa1795aSjb150015 session->keep_alive--; 119811599a4SMatt Barden 1204163af6aSjose borrego session = smb_llist_next(ll, session); 121faa1795aSjb150015 } 1224163af6aSjose borrego smb_llist_exit(ll); 123faa1795aSjb150015 } 124da6c28aaSamw 125da6c28aaSamw /* 126da6c28aaSamw * Send a session message - supports SMB-over-NBT and SMB-over-TCP. 127a90cf9f2SGordon Ross * If an mbuf chain is provided (optional), it will be freed and 128a90cf9f2SGordon Ross * set to NULL -- unconditionally! (error or not) 129da6c28aaSamw * 130a90cf9f2SGordon Ross * Builds a I/O vector (uio/iov) to do the send from mbufs, plus one 131a90cf9f2SGordon Ross * segment for the 4-byte NBT header. 132da6c28aaSamw */ 133da6c28aaSamw int 134a90cf9f2SGordon Ross smb_session_send(smb_session_t *session, uint8_t nbt_type, mbuf_chain_t *mbc) 135da6c28aaSamw { 136a90cf9f2SGordon Ross uio_t uio; 137a90cf9f2SGordon Ross iovec_t local_iov[SMB_LOCAL_IOV_MAX]; 138a90cf9f2SGordon Ross iovec_t *alloc_iov = NULL; 139a90cf9f2SGordon Ross int alloc_sz = 0; 140a90cf9f2SGordon Ross mbuf_t *m; 141a90cf9f2SGordon Ross uint8_t nbt_hdr[NETBIOS_HDR_SZ]; 142a90cf9f2SGordon Ross uint32_t nbt_len; 143a90cf9f2SGordon Ross int i, nseg; 144da6c28aaSamw int rc; 145da6c28aaSamw 146da6c28aaSamw switch (session->s_state) { 147da6c28aaSamw case SMB_SESSION_STATE_DISCONNECTED: 148da6c28aaSamw case SMB_SESSION_STATE_TERMINATED: 149a90cf9f2SGordon Ross rc = ENOTCONN; 150a90cf9f2SGordon Ross goto out; 151a90cf9f2SGordon Ross default: 152a90cf9f2SGordon Ross break; 153a90cf9f2SGordon Ross } 154a90cf9f2SGordon Ross 155a90cf9f2SGordon Ross /* 156a90cf9f2SGordon Ross * Setup the IOV. First, count the number of IOV segments 157a90cf9f2SGordon Ross * (plus one for the NBT header) and decide whether we 158a90cf9f2SGordon Ross * need to allocate an iovec or can use local_iov; 159a90cf9f2SGordon Ross */ 160a90cf9f2SGordon Ross bzero(&uio, sizeof (uio)); 161a90cf9f2SGordon Ross nseg = 1; 162a90cf9f2SGordon Ross m = (mbc != NULL) ? mbc->chain : NULL; 163a90cf9f2SGordon Ross while (m != NULL) { 164a90cf9f2SGordon Ross nseg++; 165a90cf9f2SGordon Ross m = m->m_next; 166a90cf9f2SGordon Ross } 167a90cf9f2SGordon Ross if (nseg <= SMB_LOCAL_IOV_MAX) { 168a90cf9f2SGordon Ross uio.uio_iov = local_iov; 169a90cf9f2SGordon Ross } else { 170a90cf9f2SGordon Ross alloc_sz = nseg * sizeof (iovec_t); 171a90cf9f2SGordon Ross alloc_iov = kmem_alloc(alloc_sz, KM_SLEEP); 172a90cf9f2SGordon Ross uio.uio_iov = alloc_iov; 173a90cf9f2SGordon Ross } 174a90cf9f2SGordon Ross uio.uio_iovcnt = nseg; 175a90cf9f2SGordon Ross uio.uio_segflg = UIO_SYSSPACE; 176a90cf9f2SGordon Ross uio.uio_extflg = UIO_COPY_DEFAULT; 177a90cf9f2SGordon Ross 178a90cf9f2SGordon Ross /* 179a90cf9f2SGordon Ross * Build the iov list, meanwhile computing the length of 180a90cf9f2SGordon Ross * the SMB payload (to put in the NBT header). 181a90cf9f2SGordon Ross */ 182a90cf9f2SGordon Ross uio.uio_iov[0].iov_base = (void *)nbt_hdr; 183a90cf9f2SGordon Ross uio.uio_iov[0].iov_len = sizeof (nbt_hdr); 184a90cf9f2SGordon Ross i = 1; 185a90cf9f2SGordon Ross nbt_len = 0; 186a90cf9f2SGordon Ross m = (mbc != NULL) ? mbc->chain : NULL; 187a90cf9f2SGordon Ross while (m != NULL) { 188a90cf9f2SGordon Ross uio.uio_iov[i].iov_base = m->m_data; 189a90cf9f2SGordon Ross uio.uio_iov[i++].iov_len = m->m_len; 190a90cf9f2SGordon Ross nbt_len += m->m_len; 191a90cf9f2SGordon Ross m = m->m_next; 192a90cf9f2SGordon Ross } 193a90cf9f2SGordon Ross ASSERT3S(i, ==, nseg); 194a90cf9f2SGordon Ross 195a90cf9f2SGordon Ross /* 196a90cf9f2SGordon Ross * Set the NBT header, set uio_resid 197a90cf9f2SGordon Ross */ 198a90cf9f2SGordon Ross uio.uio_resid = nbt_len + NETBIOS_HDR_SZ; 199a90cf9f2SGordon Ross rc = smb_session_xprt_puthdr(session, nbt_type, nbt_len, 200a90cf9f2SGordon Ross nbt_hdr, NETBIOS_HDR_SZ); 201a90cf9f2SGordon Ross if (rc != 0) 202a90cf9f2SGordon Ross goto out; 203a90cf9f2SGordon Ross 204a90cf9f2SGordon Ross smb_server_add_txb(session->s_server, (int64_t)uio.uio_resid); 205a90cf9f2SGordon Ross rc = smb_net_send_uio(session, &uio); 206a90cf9f2SGordon Ross 207a90cf9f2SGordon Ross out: 208a90cf9f2SGordon Ross if (alloc_iov != NULL) 209a90cf9f2SGordon Ross kmem_free(alloc_iov, alloc_sz); 210da6c28aaSamw if ((mbc != NULL) && (mbc->chain != NULL)) { 211da6c28aaSamw m_freem(mbc->chain); 212da6c28aaSamw mbc->chain = NULL; 213da6c28aaSamw mbc->flags = 0; 214da6c28aaSamw } 21521b7895dSjb150015 return (rc); 216da6c28aaSamw } 217da6c28aaSamw 218da6c28aaSamw /* 219da6c28aaSamw * Read, process and respond to a NetBIOS session request. 220da6c28aaSamw * 221da6c28aaSamw * A NetBIOS session must be established for SMB-over-NetBIOS. Validate 222da6c28aaSamw * the calling and called name format and save the client NetBIOS name, 223da6c28aaSamw * which is used when a NetBIOS session is established to check for and 224da6c28aaSamw * cleanup leftover state from a previous session. 225da6c28aaSamw * 226da6c28aaSamw * Session requests are not valid for SMB-over-TCP, which is unfortunate 227da6c28aaSamw * because without the client name leftover state cannot be cleaned up 228da6c28aaSamw * if the client is behind a NAT server. 229da6c28aaSamw */ 230da6c28aaSamw static int 231a90cf9f2SGordon Ross smb_netbios_session_request(struct smb_session *session) 232da6c28aaSamw { 233da6c28aaSamw int rc; 234da6c28aaSamw char *calling_name; 235da6c28aaSamw char *called_name; 236da6c28aaSamw char client_name[NETBIOS_NAME_SZ]; 237da6c28aaSamw struct mbuf_chain mbc; 238da6c28aaSamw char *names = NULL; 239bbf6f00cSJordan Brown smb_wchar_t *wbuf = NULL; 240da6c28aaSamw smb_xprt_t hdr; 241da6c28aaSamw char *p; 242da6c28aaSamw int rc1, rc2; 243da6c28aaSamw 244da6c28aaSamw session->keep_alive = smb_keep_alive; 245da6c28aaSamw 246faa1795aSjb150015 if ((rc = smb_session_xprt_gethdr(session, &hdr)) != 0) 247faa1795aSjb150015 return (rc); 248da6c28aaSamw 249da6c28aaSamw DTRACE_PROBE2(receive__session__req__xprthdr, struct session *, session, 250da6c28aaSamw smb_xprt_t *, &hdr); 251da6c28aaSamw 252da6c28aaSamw if ((hdr.xh_type != SESSION_REQUEST) || 253da6c28aaSamw (hdr.xh_length != NETBIOS_SESSION_REQUEST_DATA_LENGTH)) { 254da6c28aaSamw DTRACE_PROBE1(receive__session__req__failed, 255da6c28aaSamw struct session *, session); 256da6c28aaSamw return (EINVAL); 257da6c28aaSamw } 258da6c28aaSamw 259da6c28aaSamw names = kmem_alloc(hdr.xh_length, KM_SLEEP); 260da6c28aaSamw 261da6c28aaSamw if ((rc = smb_sorecv(session->sock, names, hdr.xh_length)) != 0) { 262da6c28aaSamw kmem_free(names, hdr.xh_length); 263da6c28aaSamw DTRACE_PROBE1(receive__session__req__failed, 264da6c28aaSamw struct session *, session); 265da6c28aaSamw return (rc); 266da6c28aaSamw } 267da6c28aaSamw 268da6c28aaSamw DTRACE_PROBE3(receive__session__req__data, struct session *, session, 269da6c28aaSamw char *, names, uint32_t, hdr.xh_length); 270da6c28aaSamw 271da6c28aaSamw called_name = &names[0]; 272da6c28aaSamw calling_name = &names[NETBIOS_ENCODED_NAME_SZ + 2]; 273da6c28aaSamw 274da6c28aaSamw rc1 = netbios_name_isvalid(called_name, 0); 275da6c28aaSamw rc2 = netbios_name_isvalid(calling_name, client_name); 276da6c28aaSamw 277da6c28aaSamw if (rc1 == 0 || rc2 == 0) { 278da6c28aaSamw 279da6c28aaSamw DTRACE_PROBE3(receive__invalid__session__req, 280da6c28aaSamw struct session *, session, char *, names, 281da6c28aaSamw uint32_t, hdr.xh_length); 282da6c28aaSamw 283da6c28aaSamw kmem_free(names, hdr.xh_length); 284da6c28aaSamw MBC_INIT(&mbc, MAX_DATAGRAM_LENGTH); 2853db3f65cSamw (void) smb_mbc_encodef(&mbc, "b", 286da6c28aaSamw DATAGRAM_INVALID_SOURCE_NAME_FORMAT); 287da6c28aaSamw (void) smb_session_send(session, NEGATIVE_SESSION_RESPONSE, 288da6c28aaSamw &mbc); 289da6c28aaSamw return (EINVAL); 290da6c28aaSamw } 291da6c28aaSamw 292da6c28aaSamw DTRACE_PROBE3(receive__session__req__calling__decoded, 293da6c28aaSamw struct session *, session, 294da6c28aaSamw char *, calling_name, char *, client_name); 295da6c28aaSamw 296da6c28aaSamw /* 297da6c28aaSamw * The client NetBIOS name is in oem codepage format. 298da6c28aaSamw * We need to convert it to unicode and store it in 299da6c28aaSamw * multi-byte format. We also need to strip off any 300da6c28aaSamw * spaces added as part of the NetBIOS name encoding. 301da6c28aaSamw */ 302bbf6f00cSJordan Brown wbuf = kmem_alloc((SMB_PI_MAX_HOST * sizeof (smb_wchar_t)), KM_SLEEP); 303bbf6f00cSJordan Brown (void) oemtoucs(wbuf, client_name, SMB_PI_MAX_HOST, OEM_CPG_850); 304bbf6f00cSJordan Brown (void) smb_wcstombs(session->workstation, wbuf, SMB_PI_MAX_HOST); 305bbf6f00cSJordan Brown kmem_free(wbuf, (SMB_PI_MAX_HOST * sizeof (smb_wchar_t))); 306da6c28aaSamw 307da6c28aaSamw if ((p = strchr(session->workstation, ' ')) != 0) 308da6c28aaSamw *p = '\0'; 309da6c28aaSamw 310da6c28aaSamw kmem_free(names, hdr.xh_length); 311da6c28aaSamw return (smb_session_send(session, POSITIVE_SESSION_RESPONSE, NULL)); 312da6c28aaSamw } 313da6c28aaSamw 314da6c28aaSamw /* 315da6c28aaSamw * Read 4-byte header from the session socket and build an in-memory 316da6c28aaSamw * session transport header. See smb_xprt_t definition for header 317da6c28aaSamw * format information. 318da6c28aaSamw * 319da6c28aaSamw * Direct hosted NetBIOS-less SMB (SMB-over-TCP) uses port 445. The 320da6c28aaSamw * first byte of the four-byte header must be 0 and the next three 321da6c28aaSamw * bytes contain the length of the remaining data. 322da6c28aaSamw */ 323da6c28aaSamw int 324da6c28aaSamw smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr) 325da6c28aaSamw { 326faa1795aSjb150015 int rc; 327da6c28aaSamw unsigned char buf[NETBIOS_HDR_SZ]; 328da6c28aaSamw 329faa1795aSjb150015 if ((rc = smb_sorecv(session->sock, buf, NETBIOS_HDR_SZ)) != 0) 330faa1795aSjb150015 return (rc); 331da6c28aaSamw 332da6c28aaSamw switch (session->s_local_port) { 333a0aa776eSAlan Wright case IPPORT_NETBIOS_SSN: 334da6c28aaSamw ret_hdr->xh_type = buf[0]; 335da6c28aaSamw ret_hdr->xh_length = (((uint32_t)buf[1] & 1) << 16) | 336da6c28aaSamw ((uint32_t)buf[2] << 8) | 337da6c28aaSamw ((uint32_t)buf[3]); 338da6c28aaSamw break; 339da6c28aaSamw 340a0aa776eSAlan Wright case IPPORT_SMB: 341da6c28aaSamw ret_hdr->xh_type = buf[0]; 342da6c28aaSamw 343da6c28aaSamw if (ret_hdr->xh_type != 0) { 34449b5df1eSGordon Ross cmn_err(CE_WARN, "invalid NBT type (%u) from %s", 34549b5df1eSGordon Ross ret_hdr->xh_type, session->ip_addr_str); 346faa1795aSjb150015 return (EPROTO); 347da6c28aaSamw } 348da6c28aaSamw 349da6c28aaSamw ret_hdr->xh_length = ((uint32_t)buf[1] << 16) | 350da6c28aaSamw ((uint32_t)buf[2] << 8) | 351da6c28aaSamw ((uint32_t)buf[3]); 352da6c28aaSamw break; 353da6c28aaSamw 354da6c28aaSamw default: 3557f667e74Sjose borrego cmn_err(CE_WARN, "invalid port %u", session->s_local_port); 356faa1795aSjb150015 return (EPROTO); 357da6c28aaSamw } 358da6c28aaSamw 359da6c28aaSamw return (0); 360da6c28aaSamw } 361da6c28aaSamw 362da6c28aaSamw /* 363da6c28aaSamw * Encode a transport session packet header into a 4-byte buffer. 364da6c28aaSamw */ 365da6c28aaSamw static int 366a90cf9f2SGordon Ross smb_session_xprt_puthdr(smb_session_t *session, 367a90cf9f2SGordon Ross uint8_t msg_type, uint32_t msg_length, 368da6c28aaSamw uint8_t *buf, size_t buflen) 369da6c28aaSamw { 370a90cf9f2SGordon Ross if (buf == NULL || buflen < NETBIOS_HDR_SZ) { 371da6c28aaSamw return (-1); 372da6c28aaSamw } 373da6c28aaSamw 374da6c28aaSamw switch (session->s_local_port) { 375a0aa776eSAlan Wright case IPPORT_NETBIOS_SSN: 376a90cf9f2SGordon Ross /* Per RFC 1001, 1002: msg. len < 128KB */ 377a90cf9f2SGordon Ross if (msg_length >= (1 << 17)) 378a90cf9f2SGordon Ross return (-1); 379a90cf9f2SGordon Ross buf[0] = msg_type; 380a90cf9f2SGordon Ross buf[1] = ((msg_length >> 16) & 1); 381a90cf9f2SGordon Ross buf[2] = (msg_length >> 8) & 0xff; 382a90cf9f2SGordon Ross buf[3] = msg_length & 0xff; 383da6c28aaSamw break; 384da6c28aaSamw 385a0aa776eSAlan Wright case IPPORT_SMB: 386a90cf9f2SGordon Ross /* 387a90cf9f2SGordon Ross * SMB over TCP is like NetBIOS but the one byte 388a90cf9f2SGordon Ross * message type is always zero, and the length 389a90cf9f2SGordon Ross * part is three bytes. It could actually use 390a90cf9f2SGordon Ross * longer messages, but this is conservative. 391a90cf9f2SGordon Ross */ 392a90cf9f2SGordon Ross if (msg_length >= (1 << 24)) 393a90cf9f2SGordon Ross return (-1); 394a90cf9f2SGordon Ross buf[0] = msg_type; 395a90cf9f2SGordon Ross buf[1] = (msg_length >> 16) & 0xff; 396a90cf9f2SGordon Ross buf[2] = (msg_length >> 8) & 0xff; 397a90cf9f2SGordon Ross buf[3] = msg_length & 0xff; 398da6c28aaSamw break; 399da6c28aaSamw 400da6c28aaSamw default: 4017f667e74Sjose borrego cmn_err(CE_WARN, "invalid port %u", session->s_local_port); 402da6c28aaSamw return (-1); 403da6c28aaSamw } 404da6c28aaSamw 405da6c28aaSamw return (0); 406da6c28aaSamw } 407da6c28aaSamw 408faa1795aSjb150015 static void 409da6c28aaSamw smb_request_init_command_mbuf(smb_request_t *sr) 410da6c28aaSamw { 411da6c28aaSamw 412da6c28aaSamw /* 4137f3ef643SGordon Ross * Setup mbuf using the buffer we allocated. 414da6c28aaSamw */ 4157f3ef643SGordon Ross MBC_ATTACH_BUF(&sr->command, sr->sr_request_buf, sr->sr_req_length); 416da6c28aaSamw 417da6c28aaSamw sr->command.flags = 0; 4187f3ef643SGordon Ross sr->command.shadow_of = NULL; 419da6c28aaSamw } 420da6c28aaSamw 421da6c28aaSamw /* 422da6c28aaSamw * smb_request_cancel 423da6c28aaSamw * 424da6c28aaSamw * Handle a cancel for a request properly depending on the current request 425da6c28aaSamw * state. 426da6c28aaSamw */ 427da6c28aaSamw void 428da6c28aaSamw smb_request_cancel(smb_request_t *sr) 429da6c28aaSamw { 4305677e049SGordon Ross void (*cancel_method)(smb_request_t *) = NULL; 4315677e049SGordon Ross 432da6c28aaSamw mutex_enter(&sr->sr_mutex); 433da6c28aaSamw switch (sr->sr_state) { 434da6c28aaSamw 435584e0fceSGordon Ross case SMB_REQ_STATE_INITIALIZING: 436da6c28aaSamw case SMB_REQ_STATE_SUBMITTED: 437da6c28aaSamw case SMB_REQ_STATE_ACTIVE: 438da6c28aaSamw case SMB_REQ_STATE_CLEANED_UP: 4395677e049SGordon Ross sr->sr_state = SMB_REQ_STATE_CANCELLED; 440da6c28aaSamw break; 441da6c28aaSamw 442b210fedeSGordon Ross case SMB_REQ_STATE_WAITING_AUTH: 443bfe5e737SGordon Ross case SMB_REQ_STATE_WAITING_FCN1: 444bfe5e737SGordon Ross case SMB_REQ_STATE_WAITING_LOCK: 445b210fedeSGordon Ross case SMB_REQ_STATE_WAITING_PIPE: 446da6c28aaSamw /* 4475677e049SGordon Ross * These are states that have a cancel_method. 4485677e049SGordon Ross * Make the state change now, to ensure that 4495677e049SGordon Ross * we call cancel_method exactly once. Do the 4505677e049SGordon Ross * method call below, after we drop sr_mutex. 4515677e049SGordon Ross * When the cancelled request thread resumes, 4525677e049SGordon Ross * it should re-take sr_mutex and set sr_state 4535677e049SGordon Ross * to CANCELLED, then return STATUS_CANCELLED. 454da6c28aaSamw */ 4555677e049SGordon Ross sr->sr_state = SMB_REQ_STATE_CANCEL_PENDING; 4565677e049SGordon Ross cancel_method = sr->cancel_method; 4575677e049SGordon Ross VERIFY(cancel_method != NULL); 458da6c28aaSamw break; 459da6c28aaSamw 460bfe5e737SGordon Ross case SMB_REQ_STATE_WAITING_FCN2: 461da6c28aaSamw case SMB_REQ_STATE_COMPLETED: 462bfe5e737SGordon Ross case SMB_REQ_STATE_CANCEL_PENDING: 4635677e049SGordon Ross case SMB_REQ_STATE_CANCELLED: 464da6c28aaSamw /* 465da6c28aaSamw * No action required for these states since the request 466da6c28aaSamw * is completing. 467da6c28aaSamw */ 468da6c28aaSamw break; 469584e0fceSGordon Ross 470584e0fceSGordon Ross case SMB_REQ_STATE_FREE: 471da6c28aaSamw default: 4722c2961f8Sjose borrego SMB_PANIC(); 473da6c28aaSamw } 474da6c28aaSamw mutex_exit(&sr->sr_mutex); 4755677e049SGordon Ross 4765677e049SGordon Ross if (cancel_method != NULL) { 4775677e049SGordon Ross cancel_method(sr); 4785677e049SGordon Ross } 479da6c28aaSamw } 480da6c28aaSamw 481da6c28aaSamw /* 4824163af6aSjose borrego * smb_session_receiver 483da6c28aaSamw * 4844163af6aSjose borrego * Receives request from the network and dispatches them to a worker. 485811599a4SMatt Barden * 486811599a4SMatt Barden * When we receive a disconnect here, it _could_ be due to the server 487811599a4SMatt Barden * having initiated disconnect, in which case the session state will be 488811599a4SMatt Barden * SMB_SESSION_STATE_TERMINATED and we want to keep that state so later 489811599a4SMatt Barden * tear-down logic will know which side initiated. 490da6c28aaSamw */ 4914163af6aSjose borrego void 4924163af6aSjose borrego smb_session_receiver(smb_session_t *session) 493da6c28aaSamw { 494b819cea2SGordon Ross int rc = 0; 495*817fa55fSGordon Ross timeout_id_t tmo = NULL; 496da6c28aaSamw 4974163af6aSjose borrego SMB_SESSION_VALID(session); 4984163af6aSjose borrego 4994163af6aSjose borrego session->s_thread = curthread; 500da6c28aaSamw 501a0aa776eSAlan Wright if (session->s_local_port == IPPORT_NETBIOS_SSN) { 502a90cf9f2SGordon Ross rc = smb_netbios_session_request(session); 5034163af6aSjose borrego if (rc != 0) { 504faa1795aSjb150015 smb_rwx_rwenter(&session->s_lock, RW_WRITER); 505811599a4SMatt Barden if (session->s_state != SMB_SESSION_STATE_TERMINATED) 506811599a4SMatt Barden session->s_state = 507811599a4SMatt Barden SMB_SESSION_STATE_DISCONNECTED; 508faa1795aSjb150015 smb_rwx_rwexit(&session->s_lock); 5094163af6aSjose borrego return; 510faa1795aSjb150015 } 511faa1795aSjb150015 } 512da6c28aaSamw 513da6c28aaSamw smb_rwx_rwenter(&session->s_lock, RW_WRITER); 514da6c28aaSamw session->s_state = SMB_SESSION_STATE_ESTABLISHED; 515*817fa55fSGordon Ross session->s_auth_tmo = timeout((tmo_func_t)smb_session_disconnect, 516*817fa55fSGordon Ross session, SEC_TO_TICK(smb_session_auth_tmo)); 517da6c28aaSamw smb_rwx_rwexit(&session->s_lock); 518da6c28aaSamw 519a90cf9f2SGordon Ross (void) smb_session_reader(session); 520da6c28aaSamw 521da6c28aaSamw smb_rwx_rwenter(&session->s_lock, RW_WRITER); 522811599a4SMatt Barden if (session->s_state != SMB_SESSION_STATE_TERMINATED) 523da6c28aaSamw session->s_state = SMB_SESSION_STATE_DISCONNECTED; 524*817fa55fSGordon Ross tmo = session->s_auth_tmo; 525*817fa55fSGordon Ross session->s_auth_tmo = NULL; 526da6c28aaSamw smb_rwx_rwexit(&session->s_lock); 527da6c28aaSamw 528*817fa55fSGordon Ross /* Timeout callback takes s_lock. See untimeout(9f) */ 529*817fa55fSGordon Ross if (tmo != NULL) 530*817fa55fSGordon Ross (void) untimeout(tmo); 531*817fa55fSGordon Ross 532faa1795aSjb150015 smb_soshutdown(session->sock); 533faa1795aSjb150015 534da6c28aaSamw DTRACE_PROBE2(session__drop, struct session *, session, int, rc); 535da6c28aaSamw 536da6c28aaSamw smb_session_cancel(session); 537da6c28aaSamw /* 538da6c28aaSamw * At this point everything related to the session should have been 539da6c28aaSamw * cleaned up and we expect that nothing will attempt to use the 540da6c28aaSamw * socket. 541da6c28aaSamw */ 5424163af6aSjose borrego } 543da6c28aaSamw 5444163af6aSjose borrego /* 5454163af6aSjose borrego * smb_session_disconnect 5464163af6aSjose borrego * 547811599a4SMatt Barden * Server-initiated disconnect (i.e. server shutdown) 5484163af6aSjose borrego */ 5494163af6aSjose borrego void 5504163af6aSjose borrego smb_session_disconnect(smb_session_t *session) 5514163af6aSjose borrego { 5524163af6aSjose borrego SMB_SESSION_VALID(session); 5534163af6aSjose borrego 5544163af6aSjose borrego smb_rwx_rwenter(&session->s_lock, RW_WRITER); 5554163af6aSjose borrego switch (session->s_state) { 5564163af6aSjose borrego case SMB_SESSION_STATE_INITIALIZED: 5574163af6aSjose borrego case SMB_SESSION_STATE_CONNECTED: 5584163af6aSjose borrego case SMB_SESSION_STATE_ESTABLISHED: 5594163af6aSjose borrego case SMB_SESSION_STATE_NEGOTIATED: 5604163af6aSjose borrego smb_soshutdown(session->sock); 561811599a4SMatt Barden session->s_state = SMB_SESSION_STATE_TERMINATED; 562811599a4SMatt Barden break; 5634163af6aSjose borrego case SMB_SESSION_STATE_DISCONNECTED: 5644163af6aSjose borrego case SMB_SESSION_STATE_TERMINATED: 5654163af6aSjose borrego break; 5664163af6aSjose borrego } 5674163af6aSjose borrego smb_rwx_rwexit(&session->s_lock); 568da6c28aaSamw } 569da6c28aaSamw 570da6c28aaSamw /* 571da6c28aaSamw * Read and process SMB requests. 572da6c28aaSamw * 573da6c28aaSamw * Returns: 574da6c28aaSamw * 0 Success 575da6c28aaSamw * 1 Unable to read transport header 576da6c28aaSamw * 2 Invalid transport header type 577da6c28aaSamw * 3 Invalid SMB length (too small) 578da6c28aaSamw * 4 Unable to read SMB header 579da6c28aaSamw * 5 Invalid SMB header (bad magic number) 580da6c28aaSamw * 6 Unable to read SMB data 581da6c28aaSamw */ 582da6c28aaSamw static int 583a90cf9f2SGordon Ross smb_session_reader(smb_session_t *session) 584da6c28aaSamw { 585148c5f43SAlan Wright smb_server_t *sv; 586faa1795aSjb150015 smb_request_t *sr = NULL; 587da6c28aaSamw smb_xprt_t hdr; 588da6c28aaSamw uint8_t *req_buf; 589da6c28aaSamw uint32_t resid; 590da6c28aaSamw int rc; 591da6c28aaSamw 592148c5f43SAlan Wright sv = session->s_server; 593148c5f43SAlan Wright 594faa1795aSjb150015 for (;;) { 595da6c28aaSamw 596faa1795aSjb150015 rc = smb_session_xprt_gethdr(session, &hdr); 597faa1795aSjb150015 if (rc) 598faa1795aSjb150015 return (rc); 599faa1795aSjb150015 600faa1795aSjb150015 DTRACE_PROBE2(session__receive__xprthdr, session_t *, session, 601da6c28aaSamw smb_xprt_t *, &hdr); 602da6c28aaSamw 603da6c28aaSamw if (hdr.xh_type != SESSION_MESSAGE) { 604da6c28aaSamw /* 605faa1795aSjb150015 * Anything other than SESSION_MESSAGE or 606faa1795aSjb150015 * SESSION_KEEP_ALIVE is an error. A SESSION_REQUEST 607faa1795aSjb150015 * may indicate a new session request but we need to 608faa1795aSjb150015 * close this session and we can treat it as an error 609faa1795aSjb150015 * here. 610da6c28aaSamw */ 611da6c28aaSamw if (hdr.xh_type == SESSION_KEEP_ALIVE) { 612da6c28aaSamw session->keep_alive = smb_keep_alive; 613faa1795aSjb150015 continue; 614da6c28aaSamw } 615faa1795aSjb150015 return (EPROTO); 616da6c28aaSamw } 617da6c28aaSamw 618a90cf9f2SGordon Ross if (hdr.xh_length == 0) { 619a90cf9f2SGordon Ross /* zero length is another form of keep alive */ 620a90cf9f2SGordon Ross session->keep_alive = smb_keep_alive; 621a90cf9f2SGordon Ross continue; 622a90cf9f2SGordon Ross } 623a90cf9f2SGordon Ross 624da6c28aaSamw if (hdr.xh_length < SMB_HEADER_LEN) 625faa1795aSjb150015 return (EPROTO); 626a90cf9f2SGordon Ross if (hdr.xh_length > session->cmd_max_bytes) 627a90cf9f2SGordon Ross return (EPROTO); 628da6c28aaSamw 629da6c28aaSamw session->keep_alive = smb_keep_alive; 630a90cf9f2SGordon Ross 631da6c28aaSamw /* 632a90cf9f2SGordon Ross * Allocate a request context, read the whole message. 633811599a4SMatt Barden * If the request alloc fails, we've disconnected 634811599a4SMatt Barden * and won't be able to send the reply anyway, so bail now. 635da6c28aaSamw */ 6369c856e86SMatt Barden if ((sr = smb_request_alloc(session, hdr.xh_length)) == NULL) 6379c856e86SMatt Barden break; 638da6c28aaSamw 639da6c28aaSamw req_buf = (uint8_t *)sr->sr_request_buf; 640da6c28aaSamw resid = hdr.xh_length; 641da6c28aaSamw 642faa1795aSjb150015 rc = smb_sorecv(session->sock, req_buf, resid); 643faa1795aSjb150015 if (rc) { 644da6c28aaSamw smb_request_free(sr); 645a90cf9f2SGordon Ross break; 646da6c28aaSamw } 647a90cf9f2SGordon Ross 648ac2bf314SMatt Barden /* accounting: received bytes */ 649148c5f43SAlan Wright smb_server_add_rxb(sv, 650148c5f43SAlan Wright (int64_t)(hdr.xh_length + NETBIOS_HDR_SZ)); 651a90cf9f2SGordon Ross 652da6c28aaSamw /* 653da6c28aaSamw * Initialize command MBC to represent the received data. 654da6c28aaSamw */ 655da6c28aaSamw smb_request_init_command_mbuf(sr); 656da6c28aaSamw 657da6c28aaSamw DTRACE_PROBE1(session__receive__smb, smb_request_t *, sr); 658da6c28aaSamw 659a90cf9f2SGordon Ross rc = session->newrq_func(sr); 660a90cf9f2SGordon Ross sr = NULL; /* enqueued or freed */ 661a90cf9f2SGordon Ross if (rc != 0) 662a90cf9f2SGordon Ross break; 6630897f7fbSGordon Ross 6640897f7fbSGordon Ross /* See notes where this is defined (above). */ 6650897f7fbSGordon Ross if (smb_reader_delay) { 6660897f7fbSGordon Ross delay(MSEC_TO_TICK(smb_reader_delay)); 6670897f7fbSGordon Ross } 668148c5f43SAlan Wright } 669a90cf9f2SGordon Ross return (rc); 670148c5f43SAlan Wright } 671a90cf9f2SGordon Ross 672a90cf9f2SGordon Ross /* 673a90cf9f2SGordon Ross * This is the initial handler for new smb requests, called from 674a90cf9f2SGordon Ross * from smb_session_reader when we have not yet seen any requests. 675a90cf9f2SGordon Ross * The first SMB request must be "negotiate", which determines 676a90cf9f2SGordon Ross * which protocol and dialect we'll be using. That's the ONLY 677a90cf9f2SGordon Ross * request type handled here, because with all later requests, 678a90cf9f2SGordon Ross * we know the protocol and handle those with either the SMB1 or 679a90cf9f2SGordon Ross * SMB2 handlers: smb1sr_post() or smb2sr_post(). 680a90cf9f2SGordon Ross * Those do NOT allow SMB negotiate, because that's only allowed 681a90cf9f2SGordon Ross * as the first request on new session. 682a90cf9f2SGordon Ross * 683a90cf9f2SGordon Ross * This and other "post a request" handlers must either enqueue 684a90cf9f2SGordon Ross * the new request for the session taskq, or smb_request_free it 685a90cf9f2SGordon Ross * (in case we've decided to drop this connection). In this 686a90cf9f2SGordon Ross * (special) new request handler, we always free the request. 68793bc28dbSGordon Ross * 68893bc28dbSGordon Ross * Return value is 0 for success, and anything else will 68993bc28dbSGordon Ross * terminate the reader thread (drop the connection). 690a90cf9f2SGordon Ross */ 691a90cf9f2SGordon Ross static int 692a90cf9f2SGordon Ross smbsr_newrq_initial(smb_request_t *sr) 693a90cf9f2SGordon Ross { 694a90cf9f2SGordon Ross uint32_t magic; 695a90cf9f2SGordon Ross int rc = EPROTO; 696a90cf9f2SGordon Ross 697a90cf9f2SGordon Ross mutex_enter(&sr->sr_mutex); 698a90cf9f2SGordon Ross sr->sr_state = SMB_REQ_STATE_ACTIVE; 699a90cf9f2SGordon Ross mutex_exit(&sr->sr_mutex); 700a90cf9f2SGordon Ross 701a90cf9f2SGordon Ross magic = SMB_READ_PROTOCOL(sr->sr_request_buf); 702a90cf9f2SGordon Ross if (magic == SMB_PROTOCOL_MAGIC) 703a90cf9f2SGordon Ross rc = smb1_newrq_negotiate(sr); 704a90cf9f2SGordon Ross if (magic == SMB2_PROTOCOL_MAGIC) 705a90cf9f2SGordon Ross rc = smb2_newrq_negotiate(sr); 706a90cf9f2SGordon Ross 707a90cf9f2SGordon Ross mutex_enter(&sr->sr_mutex); 708a90cf9f2SGordon Ross sr->sr_state = SMB_REQ_STATE_COMPLETED; 709a90cf9f2SGordon Ross mutex_exit(&sr->sr_mutex); 710a90cf9f2SGordon Ross 711a90cf9f2SGordon Ross smb_request_free(sr); 712a90cf9f2SGordon Ross return (rc); 713da6c28aaSamw } 714da6c28aaSamw 715da6c28aaSamw /* 716a0aa776eSAlan Wright * Port will be IPPORT_NETBIOS_SSN or IPPORT_SMB. 717da6c28aaSamw */ 718da6c28aaSamw smb_session_t * 7197f667e74Sjose borrego smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv, 7207f667e74Sjose borrego int family) 721da6c28aaSamw { 722da6c28aaSamw struct sockaddr_in sin; 7230f1702c5SYu Xiangning socklen_t slen; 7247f667e74Sjose borrego struct sockaddr_in6 sin6; 725da6c28aaSamw smb_session_t *session; 726d3d50737SRafael Vanoni int64_t now; 727a90cf9f2SGordon Ross uint16_t rport; 728da6c28aaSamw 7298622ec45SGordon Ross session = kmem_cache_alloc(smb_cache_session, KM_SLEEP); 730da6c28aaSamw bzero(session, sizeof (smb_session_t)); 731da6c28aaSamw 732da6c28aaSamw if (smb_idpool_constructor(&session->s_uid_pool)) { 7338622ec45SGordon Ross kmem_cache_free(smb_cache_session, session); 734da6c28aaSamw return (NULL); 735da6c28aaSamw } 7363b13a1efSThomas Keiser if (smb_idpool_constructor(&session->s_tid_pool)) { 7373b13a1efSThomas Keiser smb_idpool_destructor(&session->s_uid_pool); 7388622ec45SGordon Ross kmem_cache_free(smb_cache_session, session); 7393b13a1efSThomas Keiser return (NULL); 7403b13a1efSThomas Keiser } 741da6c28aaSamw 742d3d50737SRafael Vanoni now = ddi_get_lbolt64(); 743d3d50737SRafael Vanoni 744811599a4SMatt Barden session->s_server = sv; 745da6c28aaSamw session->s_kid = SMB_NEW_KID(); 746faa1795aSjb150015 session->s_state = SMB_SESSION_STATE_INITIALIZED; 747da6c28aaSamw session->native_os = NATIVE_OS_UNKNOWN; 748d3d50737SRafael Vanoni session->opentime = now; 749da6c28aaSamw session->keep_alive = smb_keep_alive; 750d3d50737SRafael Vanoni session->activity_timestamp = now; 751f9bc6dadSDmitry.Savitsky@nexenta.com smb_session_genkey(session); 752f9bc6dadSDmitry.Savitsky@nexenta.com 753a90cf9f2SGordon Ross mutex_init(&session->s_credits_mutex, NULL, MUTEX_DEFAULT, NULL); 754a90cf9f2SGordon Ross 755da6c28aaSamw smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t), 756da6c28aaSamw offsetof(smb_request_t, sr_session_lnd)); 757da6c28aaSamw 758da6c28aaSamw smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t), 759da6c28aaSamw offsetof(smb_user_t, u_lnd)); 760da6c28aaSamw 7613b13a1efSThomas Keiser smb_llist_constructor(&session->s_tree_list, sizeof (smb_tree_t), 7623b13a1efSThomas Keiser offsetof(smb_tree_t, t_lnd)); 7633b13a1efSThomas Keiser 764da6c28aaSamw smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t), 765da6c28aaSamw offsetof(smb_xa_t, xa_lnd)); 766da6c28aaSamw 7675cdbe942Sjb150015 smb_net_txl_constructor(&session->s_txlst); 7685cdbe942Sjb150015 769da6c28aaSamw smb_rwx_init(&session->s_lock); 770da6c28aaSamw 7718d94f651SGordon Ross session->s_srqueue = &sv->sv_srqueue; 7728d94f651SGordon Ross smb_server_get_cfg(sv, &session->s_cfg); 7738d94f651SGordon Ross 7748d94f651SGordon Ross if (new_so == NULL) { 7758d94f651SGordon Ross /* 7768d94f651SGordon Ross * This call is creating the special "server" session, 7778d94f651SGordon Ross * used for kshare export, oplock breaks, CA import. 7788d94f651SGordon Ross * CA import creates temporary trees on this session 7798d94f651SGordon Ross * and those should never get map/unmap up-calls, so 7808d94f651SGordon Ross * force the map/unmap flags zero on this session. 7818d94f651SGordon Ross * Set a "modern" dialect for CA import too, so 7828d94f651SGordon Ross * pathname parse doesn't do OS/2 stuff, etc. 7838d94f651SGordon Ross */ 7848d94f651SGordon Ross session->s_cfg.skc_execflags = 0; 7858d94f651SGordon Ross session->dialect = session->s_cfg.skc_max_protocol; 7868d94f651SGordon Ross } else { 7877f667e74Sjose borrego if (family == AF_INET) { 7880f1702c5SYu Xiangning slen = sizeof (sin); 7897f667e74Sjose borrego (void) ksocket_getsockname(new_so, 7907f667e74Sjose borrego (struct sockaddr *)&sin, &slen, CRED()); 791fc724630SAlan Wright bcopy(&sin.sin_addr, 792fc724630SAlan Wright &session->local_ipaddr.au_addr.au_ipv4, 793fc724630SAlan Wright sizeof (in_addr_t)); 794fc724630SAlan Wright slen = sizeof (sin); 7957f667e74Sjose borrego (void) ksocket_getpeername(new_so, 7967f667e74Sjose borrego (struct sockaddr *)&sin, &slen, CRED()); 797fc724630SAlan Wright bcopy(&sin.sin_addr, 798fc724630SAlan Wright &session->ipaddr.au_addr.au_ipv4, 799fc724630SAlan Wright sizeof (in_addr_t)); 800a90cf9f2SGordon Ross rport = sin.sin_port; 8017f667e74Sjose borrego } else { 8027f667e74Sjose borrego slen = sizeof (sin6); 8037f667e74Sjose borrego (void) ksocket_getsockname(new_so, 8047f667e74Sjose borrego (struct sockaddr *)&sin6, &slen, CRED()); 805fc724630SAlan Wright bcopy(&sin6.sin6_addr, 806fc724630SAlan Wright &session->local_ipaddr.au_addr.au_ipv6, 807fc724630SAlan Wright sizeof (in6_addr_t)); 808fc724630SAlan Wright slen = sizeof (sin6); 8097f667e74Sjose borrego (void) ksocket_getpeername(new_so, 8107f667e74Sjose borrego (struct sockaddr *)&sin6, &slen, CRED()); 811fc724630SAlan Wright bcopy(&sin6.sin6_addr, 812fc724630SAlan Wright &session->ipaddr.au_addr.au_ipv6, 813fc724630SAlan Wright sizeof (in6_addr_t)); 814a90cf9f2SGordon Ross rport = sin6.sin6_port; 8157f667e74Sjose borrego } 8167f667e74Sjose borrego session->ipaddr.a_family = family; 8177f667e74Sjose borrego session->local_ipaddr.a_family = family; 818da6c28aaSamw session->s_local_port = port; 819a90cf9f2SGordon Ross session->s_remote_port = ntohs(rport); 820da6c28aaSamw session->sock = new_so; 82149b5df1eSGordon Ross (void) smb_inet_ntop(&session->ipaddr, 82249b5df1eSGordon Ross session->ip_addr_str, INET6_ADDRSTRLEN); 823148c5f43SAlan Wright if (port == IPPORT_NETBIOS_SSN) 824148c5f43SAlan Wright smb_server_inc_nbt_sess(sv); 825148c5f43SAlan Wright else 826148c5f43SAlan Wright smb_server_inc_tcp_sess(sv); 827faa1795aSjb150015 } 828148c5f43SAlan Wright 829a90cf9f2SGordon Ross /* 830a90cf9f2SGordon Ross * The initial new request handler is special, 831a90cf9f2SGordon Ross * and only accepts negotiation requests. 832a90cf9f2SGordon Ross */ 833a90cf9f2SGordon Ross session->newrq_func = smbsr_newrq_initial; 834a90cf9f2SGordon Ross 835a90cf9f2SGordon Ross /* These may increase in SMB2 negotiate. */ 836a90cf9f2SGordon Ross session->cmd_max_bytes = SMB_REQ_MAX_SIZE; 837a90cf9f2SGordon Ross session->reply_max_bytes = SMB_REQ_MAX_SIZE; 838a90cf9f2SGordon Ross 839da6c28aaSamw session->s_magic = SMB_SESSION_MAGIC; 840da6c28aaSamw return (session); 841da6c28aaSamw } 842da6c28aaSamw 843da6c28aaSamw void 844da6c28aaSamw smb_session_delete(smb_session_t *session) 845da6c28aaSamw { 8462c2961f8Sjose borrego 847da6c28aaSamw ASSERT(session->s_magic == SMB_SESSION_MAGIC); 848da6c28aaSamw 8491160dcf7SMatt Barden if (session->enc_mech != NULL) 8501160dcf7SMatt Barden smb3_encrypt_fini(session); 8511160dcf7SMatt Barden 852b819cea2SGordon Ross if (session->sign_fini != NULL) 853b819cea2SGordon Ross session->sign_fini(session); 854b819cea2SGordon Ross 85512b65585SGordon Ross if (session->signing.mackey != NULL) { 85612b65585SGordon Ross kmem_free(session->signing.mackey, 85712b65585SGordon Ross session->signing.mackey_len); 85812b65585SGordon Ross } 85912b65585SGordon Ross 86012b65585SGordon Ross session->s_magic = 0; 86112b65585SGordon Ross 862da6c28aaSamw smb_rwx_destroy(&session->s_lock); 8635cdbe942Sjb150015 smb_net_txl_destructor(&session->s_txlst); 8642c2961f8Sjose borrego 865a90cf9f2SGordon Ross mutex_destroy(&session->s_credits_mutex); 866a90cf9f2SGordon Ross 867da6c28aaSamw smb_slist_destructor(&session->s_req_list); 8683b13a1efSThomas Keiser smb_llist_destructor(&session->s_tree_list); 869da6c28aaSamw smb_llist_destructor(&session->s_user_list); 870da6c28aaSamw smb_llist_destructor(&session->s_xa_list); 871da6c28aaSamw 872da6c28aaSamw ASSERT(session->s_tree_cnt == 0); 873da6c28aaSamw ASSERT(session->s_file_cnt == 0); 874da6c28aaSamw ASSERT(session->s_dir_cnt == 0); 875da6c28aaSamw 8763b13a1efSThomas Keiser smb_idpool_destructor(&session->s_tid_pool); 877da6c28aaSamw smb_idpool_destructor(&session->s_uid_pool); 8784163af6aSjose borrego if (session->sock != NULL) { 8794163af6aSjose borrego if (session->s_local_port == IPPORT_NETBIOS_SSN) 8804163af6aSjose borrego smb_server_dec_nbt_sess(session->s_server); 8814163af6aSjose borrego else 8824163af6aSjose borrego smb_server_dec_tcp_sess(session->s_server); 8834163af6aSjose borrego smb_sodestroy(session->sock); 8844163af6aSjose borrego } 8858622ec45SGordon Ross kmem_cache_free(smb_cache_session, session); 886da6c28aaSamw } 887da6c28aaSamw 8882c2961f8Sjose borrego static void 889da6c28aaSamw smb_session_cancel(smb_session_t *session) 890da6c28aaSamw { 891da6c28aaSamw smb_xa_t *xa, *nextxa; 892da6c28aaSamw 893da6c28aaSamw /* All the request currently being treated must be canceled. */ 894c8ec8eeaSjose borrego smb_session_cancel_requests(session, NULL, NULL); 895da6c28aaSamw 896da6c28aaSamw /* 897da6c28aaSamw * We wait for the completion of all the requests associated with 898da6c28aaSamw * this session. 899da6c28aaSamw */ 900da6c28aaSamw smb_slist_wait_for_empty(&session->s_req_list); 901da6c28aaSamw 902da6c28aaSamw /* 903*817fa55fSGordon Ross * Cleanup transact state objects 904da6c28aaSamw */ 905da6c28aaSamw xa = smb_llist_head(&session->s_xa_list); 906da6c28aaSamw while (xa) { 907da6c28aaSamw nextxa = smb_llist_next(&session->s_xa_list, xa); 908da6c28aaSamw smb_xa_close(xa); 909da6c28aaSamw xa = nextxa; 910da6c28aaSamw } 9119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 912*817fa55fSGordon Ross /* 913*817fa55fSGordon Ross * At this point the reference count of the files and directories 914*817fa55fSGordon Ross * should be zero. It should be possible to destroy them without 915*817fa55fSGordon Ross * any problem, which should trigger the destruction of other objects. 916*817fa55fSGordon Ross */ 9179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_session_logoff(session); 918da6c28aaSamw } 919da6c28aaSamw 920c8ec8eeaSjose borrego /* 921c8ec8eeaSjose borrego * Cancel requests. If a non-null tree is specified, only requests specific 922c8ec8eeaSjose borrego * to that tree will be cancelled. If a non-null sr is specified, that sr 923c8ec8eeaSjose borrego * will be not be cancelled - this would typically be the caller's sr. 924c8ec8eeaSjose borrego */ 925da6c28aaSamw void 926da6c28aaSamw smb_session_cancel_requests( 927c8ec8eeaSjose borrego smb_session_t *session, 928c8ec8eeaSjose borrego smb_tree_t *tree, 929c8ec8eeaSjose borrego smb_request_t *exclude_sr) 930da6c28aaSamw { 931da6c28aaSamw smb_request_t *sr; 932da6c28aaSamw 933da6c28aaSamw smb_slist_enter(&session->s_req_list); 934da6c28aaSamw sr = smb_slist_head(&session->s_req_list); 935c8ec8eeaSjose borrego 936da6c28aaSamw while (sr) { 937da6c28aaSamw ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 938c8ec8eeaSjose borrego if ((sr != exclude_sr) && 939c8ec8eeaSjose borrego (tree == NULL || sr->tid_tree == tree)) 940da6c28aaSamw smb_request_cancel(sr); 941da6c28aaSamw 942c8ec8eeaSjose borrego sr = smb_slist_next(&session->s_req_list, sr); 943da6c28aaSamw } 944c8ec8eeaSjose borrego 945da6c28aaSamw smb_slist_exit(&session->s_req_list); 946da6c28aaSamw } 947da6c28aaSamw 948faa1795aSjb150015 /* 9499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Find a user on the specified session by SMB UID. 9509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 9519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_user_t * 9529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_session_lookup_uid(smb_session_t *session, uint16_t uid) 9539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 954811599a4SMatt Barden return (smb_session_lookup_uid_st(session, 0, uid, 955811599a4SMatt Barden SMB_USER_STATE_LOGGED_ON)); 956811599a4SMatt Barden } 957811599a4SMatt Barden 958811599a4SMatt Barden /* 959811599a4SMatt Barden * Find a user on the specified session by SMB2 SSNID. 960811599a4SMatt Barden */ 961811599a4SMatt Barden smb_user_t * 962811599a4SMatt Barden smb_session_lookup_ssnid(smb_session_t *session, uint64_t ssnid) 963811599a4SMatt Barden { 964811599a4SMatt Barden return (smb_session_lookup_uid_st(session, ssnid, 0, 96512b65585SGordon Ross SMB_USER_STATE_LOGGED_ON)); 96612b65585SGordon Ross } 96712b65585SGordon Ross 96812b65585SGordon Ross smb_user_t * 969811599a4SMatt Barden smb_session_lookup_uid_st(smb_session_t *session, uint64_t ssnid, 970811599a4SMatt Barden uint16_t uid, smb_user_state_t st) 97112b65585SGordon Ross { 9729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_user_t *user; 9739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_t *user_list; 9749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 9759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_SESSION_VALID(session); 9769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 9779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States user_list = &session->s_user_list; 9789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_enter(user_list, RW_READER); 9799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 980811599a4SMatt Barden for (user = smb_llist_head(user_list); 981811599a4SMatt Barden user != NULL; 982811599a4SMatt Barden user = smb_llist_next(user_list, user)) { 983811599a4SMatt Barden 9849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_USER_VALID(user); 9859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(user->u_session == session); 9869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 987811599a4SMatt Barden if (user->u_ssnid != ssnid && user->u_uid != uid) 988811599a4SMatt Barden continue; 989811599a4SMatt Barden 990811599a4SMatt Barden mutex_enter(&user->u_mutex); 991811599a4SMatt Barden if (user->u_state == st) { 992811599a4SMatt Barden // smb_user_hold_internal(user); 993811599a4SMatt Barden user->u_refcnt++; 994811599a4SMatt Barden mutex_exit(&user->u_mutex); 9959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States break; 9969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 997811599a4SMatt Barden mutex_exit(&user->u_mutex); 9989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 9999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 10009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_exit(user_list); 100112b65585SGordon Ross return (user); 10029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 10039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 10049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 10053b13a1efSThomas Keiser * Find a tree by tree-id. 10063b13a1efSThomas Keiser */ 10073b13a1efSThomas Keiser smb_tree_t * 10083b13a1efSThomas Keiser smb_session_lookup_tree( 10093b13a1efSThomas Keiser smb_session_t *session, 10103b13a1efSThomas Keiser uint16_t tid) 10113b13a1efSThomas Keiser { 10123b13a1efSThomas Keiser smb_tree_t *tree; 10133b13a1efSThomas Keiser 10143b13a1efSThomas Keiser SMB_SESSION_VALID(session); 10153b13a1efSThomas Keiser 10163b13a1efSThomas Keiser smb_llist_enter(&session->s_tree_list, RW_READER); 10173b13a1efSThomas Keiser tree = smb_llist_head(&session->s_tree_list); 10183b13a1efSThomas Keiser 10193b13a1efSThomas Keiser while (tree) { 10203b13a1efSThomas Keiser ASSERT3U(tree->t_magic, ==, SMB_TREE_MAGIC); 10213b13a1efSThomas Keiser ASSERT(tree->t_session == session); 10223b13a1efSThomas Keiser 10233b13a1efSThomas Keiser if (tree->t_tid == tid) { 10243b13a1efSThomas Keiser if (smb_tree_hold(tree)) { 10253b13a1efSThomas Keiser smb_llist_exit(&session->s_tree_list); 10263b13a1efSThomas Keiser return (tree); 10273b13a1efSThomas Keiser } else { 10283b13a1efSThomas Keiser smb_llist_exit(&session->s_tree_list); 10293b13a1efSThomas Keiser return (NULL); 10303b13a1efSThomas Keiser } 10313b13a1efSThomas Keiser } 10323b13a1efSThomas Keiser 10333b13a1efSThomas Keiser tree = smb_llist_next(&session->s_tree_list, tree); 10343b13a1efSThomas Keiser } 10353b13a1efSThomas Keiser 10363b13a1efSThomas Keiser smb_llist_exit(&session->s_tree_list); 10373b13a1efSThomas Keiser return (NULL); 10383b13a1efSThomas Keiser } 10393b13a1efSThomas Keiser 10403b13a1efSThomas Keiser /* 10413b13a1efSThomas Keiser * Disconnect all trees that match the specified client process-id. 10428d94f651SGordon Ross * Used by the SMB1 "process exit" request. 10433b13a1efSThomas Keiser */ 10443b13a1efSThomas Keiser void 10453b13a1efSThomas Keiser smb_session_close_pid( 10463b13a1efSThomas Keiser smb_session_t *session, 1047a90cf9f2SGordon Ross uint32_t pid) 10483b13a1efSThomas Keiser { 10498d94f651SGordon Ross smb_llist_t *tree_list = &session->s_tree_list; 10503b13a1efSThomas Keiser smb_tree_t *tree; 10513b13a1efSThomas Keiser 10528d94f651SGordon Ross smb_llist_enter(tree_list, RW_READER); 10533b13a1efSThomas Keiser 10548d94f651SGordon Ross tree = smb_llist_head(tree_list); 10553b13a1efSThomas Keiser while (tree) { 10568d94f651SGordon Ross if (smb_tree_hold(tree)) { 10573b13a1efSThomas Keiser smb_tree_close_pid(tree, pid); 10583b13a1efSThomas Keiser smb_tree_release(tree); 10593b13a1efSThomas Keiser } 10608d94f651SGordon Ross tree = smb_llist_next(tree_list, tree); 10618d94f651SGordon Ross } 10628d94f651SGordon Ross 10638d94f651SGordon Ross smb_llist_exit(tree_list); 10643b13a1efSThomas Keiser } 10653b13a1efSThomas Keiser 10663b13a1efSThomas Keiser static void 10678d94f651SGordon Ross smb_session_tree_dtor(void *arg) 10683b13a1efSThomas Keiser { 10698d94f651SGordon Ross smb_tree_t *tree = arg; 10703b13a1efSThomas Keiser 10713b13a1efSThomas Keiser smb_tree_disconnect(tree, B_TRUE); 10723b13a1efSThomas Keiser /* release the ref acquired during the traversal loop */ 10733b13a1efSThomas Keiser smb_tree_release(tree); 10743b13a1efSThomas Keiser } 10753b13a1efSThomas Keiser 10763b13a1efSThomas Keiser 10773b13a1efSThomas Keiser /* 10783b13a1efSThomas Keiser * Disconnect all trees that this user has connected. 10793b13a1efSThomas Keiser */ 10803b13a1efSThomas Keiser void 10813b13a1efSThomas Keiser smb_session_disconnect_owned_trees( 10823b13a1efSThomas Keiser smb_session_t *session, 10833b13a1efSThomas Keiser smb_user_t *owner) 10843b13a1efSThomas Keiser { 10853b13a1efSThomas Keiser smb_tree_t *tree; 10863b13a1efSThomas Keiser smb_llist_t *tree_list = &session->s_tree_list; 10873b13a1efSThomas Keiser 10883b13a1efSThomas Keiser SMB_SESSION_VALID(session); 10893b13a1efSThomas Keiser SMB_USER_VALID(owner); 10903b13a1efSThomas Keiser 10913b13a1efSThomas Keiser smb_llist_enter(tree_list, RW_READER); 10923b13a1efSThomas Keiser 10933b13a1efSThomas Keiser tree = smb_llist_head(tree_list); 10943b13a1efSThomas Keiser while (tree) { 10953b13a1efSThomas Keiser if ((tree->t_owner == owner) && 10963b13a1efSThomas Keiser smb_tree_hold(tree)) { 10973b13a1efSThomas Keiser /* 10983b13a1efSThomas Keiser * smb_tree_hold() succeeded, hence we are in state 10993b13a1efSThomas Keiser * SMB_TREE_STATE_CONNECTED; schedule this tree 1100811599a4SMatt Barden * for disconnect after smb_llist_exit because 1101811599a4SMatt Barden * the "unmap exec" up-call can block, and we'd 1102811599a4SMatt Barden * rather not block with the tree list locked. 11033b13a1efSThomas Keiser */ 11043b13a1efSThomas Keiser smb_llist_post(tree_list, tree, smb_session_tree_dtor); 11053b13a1efSThomas Keiser } 11063b13a1efSThomas Keiser tree = smb_llist_next(tree_list, tree); 11073b13a1efSThomas Keiser } 11083b13a1efSThomas Keiser 11093b13a1efSThomas Keiser /* drop the lock and flush the dtor queue */ 11103b13a1efSThomas Keiser smb_llist_exit(tree_list); 11113b13a1efSThomas Keiser } 11123b13a1efSThomas Keiser 11133b13a1efSThomas Keiser /* 11143b13a1efSThomas Keiser * Disconnect all trees that this user has connected. 11153b13a1efSThomas Keiser */ 1116811599a4SMatt Barden static void 11173b13a1efSThomas Keiser smb_session_disconnect_trees( 11183b13a1efSThomas Keiser smb_session_t *session) 11193b13a1efSThomas Keiser { 11208d94f651SGordon Ross smb_llist_t *tree_list = &session->s_tree_list; 11218d94f651SGordon Ross smb_tree_t *tree; 11223b13a1efSThomas Keiser 11238d94f651SGordon Ross smb_llist_enter(tree_list, RW_READER); 11243b13a1efSThomas Keiser 11258d94f651SGordon Ross tree = smb_llist_head(tree_list); 11263b13a1efSThomas Keiser while (tree) { 11278d94f651SGordon Ross if (smb_tree_hold(tree)) { 11288d94f651SGordon Ross smb_llist_post(tree_list, tree, 11298d94f651SGordon Ross smb_session_tree_dtor); 11303b13a1efSThomas Keiser } 11318d94f651SGordon Ross tree = smb_llist_next(tree_list, tree); 11328d94f651SGordon Ross } 11338d94f651SGordon Ross 11348d94f651SGordon Ross /* drop the lock and flush the dtor queue */ 11358d94f651SGordon Ross smb_llist_exit(tree_list); 11363b13a1efSThomas Keiser } 11373b13a1efSThomas Keiser 11383b13a1efSThomas Keiser /* 11398d94f651SGordon Ross * Variant of smb_session_tree_dtor that also 11408d94f651SGordon Ross * cancels requests using this tree. 11418d94f651SGordon Ross */ 11428d94f651SGordon Ross static void 11438d94f651SGordon Ross smb_session_tree_kill(void *arg) 11448d94f651SGordon Ross { 11458d94f651SGordon Ross smb_tree_t *tree = arg; 11468d94f651SGordon Ross 11478d94f651SGordon Ross SMB_TREE_VALID(tree); 11488d94f651SGordon Ross 11498d94f651SGordon Ross smb_tree_disconnect(tree, B_TRUE); 11508d94f651SGordon Ross smb_session_cancel_requests(tree->t_session, tree, NULL); 11518d94f651SGordon Ross 11528d94f651SGordon Ross /* release the ref acquired during the traversal loop */ 11538d94f651SGordon Ross smb_tree_release(tree); 11548d94f651SGordon Ross } 11558d94f651SGordon Ross 11568d94f651SGordon Ross /* 11578d94f651SGordon Ross * Disconnect all trees that match the specified share name, 11588d94f651SGordon Ross * and kill requests using those trees. 11593b13a1efSThomas Keiser */ 11603b13a1efSThomas Keiser void 11613b13a1efSThomas Keiser smb_session_disconnect_share( 11623b13a1efSThomas Keiser smb_session_t *session, 11633b13a1efSThomas Keiser const char *sharename) 11643b13a1efSThomas Keiser { 11658d94f651SGordon Ross smb_llist_t *ll; 11663b13a1efSThomas Keiser smb_tree_t *tree; 11673b13a1efSThomas Keiser 11683b13a1efSThomas Keiser SMB_SESSION_VALID(session); 11693b13a1efSThomas Keiser 11708d94f651SGordon Ross ll = &session->s_tree_list; 11718d94f651SGordon Ross smb_llist_enter(ll, RW_READER); 11728d94f651SGordon Ross 11738d94f651SGordon Ross for (tree = smb_llist_head(ll); 11748d94f651SGordon Ross tree != NULL; 11758d94f651SGordon Ross tree = smb_llist_next(ll, tree)) { 11768d94f651SGordon Ross 11778d94f651SGordon Ross SMB_TREE_VALID(tree); 11783b13a1efSThomas Keiser ASSERT(tree->t_session == session); 11798d94f651SGordon Ross 11808d94f651SGordon Ross if (smb_strcasecmp(tree->t_sharename, sharename, 0) != 0) 11818d94f651SGordon Ross continue; 11828d94f651SGordon Ross 11838d94f651SGordon Ross if (smb_tree_hold(tree)) { 11848d94f651SGordon Ross smb_llist_post(ll, tree, 11858d94f651SGordon Ross smb_session_tree_kill); 11863b13a1efSThomas Keiser } 11873b13a1efSThomas Keiser } 11883b13a1efSThomas Keiser 11898d94f651SGordon Ross smb_llist_exit(ll); 11903b13a1efSThomas Keiser } 11913b13a1efSThomas Keiser 11923b13a1efSThomas Keiser /* 11939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Logoff all users associated with the specified session. 1194811599a4SMatt Barden * 1195811599a4SMatt Barden * This is called for both server-initiated disconnect 1196811599a4SMatt Barden * (SMB_SESSION_STATE_TERMINATED) and client-initiated 1197811599a4SMatt Barden * disconnect (SMB_SESSION_STATE_DISCONNECTED). 1198811599a4SMatt Barden * If client-initiated, save durable handles. 11999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 12008d94f651SGordon Ross void 12019fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_session_logoff(smb_session_t *session) 12029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 1203811599a4SMatt Barden smb_llist_t *ulist; 12049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_user_t *user; 12059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 12069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_SESSION_VALID(session); 12079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1208811599a4SMatt Barden top: 1209811599a4SMatt Barden ulist = &session->s_user_list; 1210811599a4SMatt Barden smb_llist_enter(ulist, RW_READER); 12113b13a1efSThomas Keiser 1212811599a4SMatt Barden user = smb_llist_head(ulist); 12139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States while (user) { 12149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_USER_VALID(user); 12159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(user->u_session == session); 12169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1217811599a4SMatt Barden mutex_enter(&user->u_mutex); 121812b65585SGordon Ross switch (user->u_state) { 121912b65585SGordon Ross case SMB_USER_STATE_LOGGING_ON: 122012b65585SGordon Ross case SMB_USER_STATE_LOGGED_ON: 1221811599a4SMatt Barden // smb_user_hold_internal(user); 1222811599a4SMatt Barden user->u_refcnt++; 1223811599a4SMatt Barden mutex_exit(&user->u_mutex); 12249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_user_logoff(user); 12259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_user_release(user); 122612b65585SGordon Ross break; 122712b65585SGordon Ross 122812b65585SGordon Ross case SMB_USER_STATE_LOGGED_OFF: 122912b65585SGordon Ross case SMB_USER_STATE_LOGGING_OFF: 1230811599a4SMatt Barden mutex_exit(&user->u_mutex); 123112b65585SGordon Ross break; 123212b65585SGordon Ross 123312b65585SGordon Ross default: 1234811599a4SMatt Barden mutex_exit(&user->u_mutex); 1235*817fa55fSGordon Ross ASSERT(0); 123612b65585SGordon Ross break; 12379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 12389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1239811599a4SMatt Barden user = smb_llist_next(ulist, user); 12409fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 12419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1242811599a4SMatt Barden /* Needed below (Was the list empty?) */ 1243811599a4SMatt Barden user = smb_llist_head(ulist); 1244811599a4SMatt Barden 1245811599a4SMatt Barden smb_llist_exit(ulist); 1246811599a4SMatt Barden 1247811599a4SMatt Barden /* 1248811599a4SMatt Barden * It's possible for user objects to remain due to references 1249811599a4SMatt Barden * obtained via smb_server_lookup_ssnid(), when an SMB2 1250811599a4SMatt Barden * session setup is destroying a previous session. 1251811599a4SMatt Barden * 1252811599a4SMatt Barden * Wait for user objects to clear out (last refs. go away, 1253811599a4SMatt Barden * then smb_user_delete takes them out of the list). When 1254811599a4SMatt Barden * the last user object is removed, the session state is 1255811599a4SMatt Barden * set to SHUTDOWN and s_lock is signaled. 1256811599a4SMatt Barden * 1257811599a4SMatt Barden * Not all places that call smb_user_release necessarily 1258811599a4SMatt Barden * flush the delete queue, so after we wait for the list 1259811599a4SMatt Barden * to empty out, go back to the top and recheck the list 1260811599a4SMatt Barden * delete queue to make sure smb_user_delete happens. 1261811599a4SMatt Barden */ 1262811599a4SMatt Barden if (user == NULL) { 1263811599a4SMatt Barden /* User list is empty. */ 1264811599a4SMatt Barden smb_rwx_rwenter(&session->s_lock, RW_WRITER); 1265811599a4SMatt Barden session->s_state = SMB_SESSION_STATE_SHUTDOWN; 1266811599a4SMatt Barden smb_rwx_rwexit(&session->s_lock); 1267811599a4SMatt Barden } else { 1268811599a4SMatt Barden smb_rwx_rwenter(&session->s_lock, RW_READER); 1269811599a4SMatt Barden if (session->s_state != SMB_SESSION_STATE_SHUTDOWN) { 1270811599a4SMatt Barden (void) smb_rwx_cvwait(&session->s_lock, 1271811599a4SMatt Barden MSEC_TO_TICK(200)); 1272811599a4SMatt Barden smb_rwx_rwexit(&session->s_lock); 1273811599a4SMatt Barden goto top; 1274811599a4SMatt Barden } 1275811599a4SMatt Barden smb_rwx_rwexit(&session->s_lock); 1276811599a4SMatt Barden } 1277811599a4SMatt Barden ASSERT(session->s_state == SMB_SESSION_STATE_SHUTDOWN); 1278811599a4SMatt Barden 1279811599a4SMatt Barden /* 1280811599a4SMatt Barden * User list should be empty now. 1281811599a4SMatt Barden */ 1282811599a4SMatt Barden #ifdef DEBUG 1283811599a4SMatt Barden if (ulist->ll_count != 0) { 1284811599a4SMatt Barden cmn_err(CE_WARN, "user list not empty?"); 1285811599a4SMatt Barden debug_enter("s_user_list"); 1286811599a4SMatt Barden } 1287811599a4SMatt Barden #endif 1288811599a4SMatt Barden 1289811599a4SMatt Barden /* 1290811599a4SMatt Barden * User logoff happens first so we'll set preserve_opens 1291811599a4SMatt Barden * for client-initiated disconnect. When that's done 1292811599a4SMatt Barden * there should be no trees left, but check anyway. 1293811599a4SMatt Barden */ 1294811599a4SMatt Barden smb_session_disconnect_trees(session); 12959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 12969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 12979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 12981fcced4cSJordan Brown * Copy the session workstation/client name to buf. If the workstation 12991fcced4cSJordan Brown * is an empty string (which it will be on TCP connections), use the 13001fcced4cSJordan Brown * client IP address. 13011fcced4cSJordan Brown */ 13021fcced4cSJordan Brown void 13031fcced4cSJordan Brown smb_session_getclient(smb_session_t *sn, char *buf, size_t buflen) 13041fcced4cSJordan Brown { 13051fcced4cSJordan Brown 13061fcced4cSJordan Brown *buf = '\0'; 13071fcced4cSJordan Brown 13081fcced4cSJordan Brown if (sn->workstation[0] != '\0') { 13091fcced4cSJordan Brown (void) strlcpy(buf, sn->workstation, buflen); 13101fcced4cSJordan Brown return; 13111fcced4cSJordan Brown } 13121fcced4cSJordan Brown 131349b5df1eSGordon Ross (void) strlcpy(buf, sn->ip_addr_str, buflen); 13141fcced4cSJordan Brown } 13151fcced4cSJordan Brown 13161fcced4cSJordan Brown /* 13171fcced4cSJordan Brown * Check whether or not the specified client name is the client of this 13181fcced4cSJordan Brown * session. The name may be in UNC format (\\CLIENT). 13191fcced4cSJordan Brown * 13201fcced4cSJordan Brown * A workstation/client name is setup on NBT connections as part of the 13211fcced4cSJordan Brown * NetBIOS session request but that isn't available on TCP connections. 13221fcced4cSJordan Brown * If the session doesn't have a client name we typically return the 13231fcced4cSJordan Brown * client IP address as the workstation name on MSRPC requests. So we 13241fcced4cSJordan Brown * check for the IP address here in addition to the workstation name. 13251fcced4cSJordan Brown */ 13261fcced4cSJordan Brown boolean_t 13271fcced4cSJordan Brown smb_session_isclient(smb_session_t *sn, const char *client) 13281fcced4cSJordan Brown { 13291fcced4cSJordan Brown 13301fcced4cSJordan Brown client += strspn(client, "\\"); 13311fcced4cSJordan Brown 1332bbf6f00cSJordan Brown if (smb_strcasecmp(client, sn->workstation, 0) == 0) 13331fcced4cSJordan Brown return (B_TRUE); 13341fcced4cSJordan Brown 133549b5df1eSGordon Ross if (smb_strcasecmp(client, sn->ip_addr_str, 0) == 0) 13361fcced4cSJordan Brown return (B_TRUE); 13371fcced4cSJordan Brown 13381fcced4cSJordan Brown return (B_FALSE); 13391fcced4cSJordan Brown } 13401fcced4cSJordan Brown 13411fcced4cSJordan Brown /* 1342faa1795aSjb150015 * smb_request_alloc 1343faa1795aSjb150015 * 1344faa1795aSjb150015 * Allocate an smb_request_t structure from the kmem_cache. Partially 1345faa1795aSjb150015 * initialize the found/new request. 1346faa1795aSjb150015 * 13479c856e86SMatt Barden * Returns pointer to a request, or NULL if the session state is 13489c856e86SMatt Barden * one in which new requests are no longer allowed. 1349faa1795aSjb150015 */ 1350faa1795aSjb150015 smb_request_t * 1351faa1795aSjb150015 smb_request_alloc(smb_session_t *session, int req_length) 1352faa1795aSjb150015 { 1353faa1795aSjb150015 smb_request_t *sr; 1354faa1795aSjb150015 1355faa1795aSjb150015 ASSERT(session->s_magic == SMB_SESSION_MAGIC); 1356a90cf9f2SGordon Ross ASSERT(req_length <= session->cmd_max_bytes); 1357faa1795aSjb150015 13588622ec45SGordon Ross sr = kmem_cache_alloc(smb_cache_request, KM_SLEEP); 1359faa1795aSjb150015 1360faa1795aSjb150015 /* 1361faa1795aSjb150015 * Future: Use constructor to pre-initialize some fields. For now 1362faa1795aSjb150015 * there are so many fields that it is easiest just to zero the 1363faa1795aSjb150015 * whole thing and start over. 1364faa1795aSjb150015 */ 1365faa1795aSjb150015 bzero(sr, sizeof (smb_request_t)); 1366faa1795aSjb150015 1367faa1795aSjb150015 mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL); 1368bbf6f00cSJordan Brown smb_srm_init(sr); 1369faa1795aSjb150015 sr->session = session; 1370faa1795aSjb150015 sr->sr_server = session->s_server; 1371faa1795aSjb150015 sr->sr_gmtoff = session->s_server->si_gmtoff; 1372faa1795aSjb150015 sr->sr_cfg = &session->s_cfg; 1373faa1795aSjb150015 sr->command.max_bytes = req_length; 1374a90cf9f2SGordon Ross sr->reply.max_bytes = session->reply_max_bytes; 1375faa1795aSjb150015 sr->sr_req_length = req_length; 1376faa1795aSjb150015 if (req_length) 1377faa1795aSjb150015 sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP); 1378faa1795aSjb150015 sr->sr_magic = SMB_REQ_MAGIC; 1379faa1795aSjb150015 sr->sr_state = SMB_REQ_STATE_INITIALIZING; 13809c856e86SMatt Barden 13819c856e86SMatt Barden /* 13829c856e86SMatt Barden * Only allow new SMB requests in some states. 13839c856e86SMatt Barden */ 13849c856e86SMatt Barden smb_rwx_rwenter(&session->s_lock, RW_WRITER); 13859c856e86SMatt Barden switch (session->s_state) { 13869c856e86SMatt Barden case SMB_SESSION_STATE_CONNECTED: 13879c856e86SMatt Barden case SMB_SESSION_STATE_INITIALIZED: 13889c856e86SMatt Barden case SMB_SESSION_STATE_ESTABLISHED: 13899c856e86SMatt Barden case SMB_SESSION_STATE_NEGOTIATED: 1390faa1795aSjb150015 smb_slist_insert_tail(&session->s_req_list, sr); 13919c856e86SMatt Barden break; 13929c856e86SMatt Barden 13939c856e86SMatt Barden default: 13949c856e86SMatt Barden ASSERT(0); 13959c856e86SMatt Barden /* FALLTHROUGH */ 13969c856e86SMatt Barden case SMB_SESSION_STATE_DISCONNECTED: 1397811599a4SMatt Barden case SMB_SESSION_STATE_SHUTDOWN: 13989c856e86SMatt Barden case SMB_SESSION_STATE_TERMINATED: 13999c856e86SMatt Barden /* Disallow new requests in these states. */ 14009c856e86SMatt Barden if (sr->sr_request_buf) 14019c856e86SMatt Barden kmem_free(sr->sr_request_buf, sr->sr_req_length); 14029c856e86SMatt Barden sr->session = NULL; 14039c856e86SMatt Barden sr->sr_magic = 0; 14049c856e86SMatt Barden mutex_destroy(&sr->sr_mutex); 14059c856e86SMatt Barden kmem_cache_free(smb_cache_request, sr); 14069c856e86SMatt Barden sr = NULL; 14079c856e86SMatt Barden break; 14089c856e86SMatt Barden } 14099c856e86SMatt Barden smb_rwx_rwexit(&session->s_lock); 14109c856e86SMatt Barden 1411faa1795aSjb150015 return (sr); 1412faa1795aSjb150015 } 1413faa1795aSjb150015 1414faa1795aSjb150015 /* 1415faa1795aSjb150015 * smb_request_free 1416faa1795aSjb150015 * 1417faa1795aSjb150015 * release the memories which have been allocated for a smb request. 1418faa1795aSjb150015 */ 1419faa1795aSjb150015 void 1420faa1795aSjb150015 smb_request_free(smb_request_t *sr) 1421faa1795aSjb150015 { 1422faa1795aSjb150015 ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 1423faa1795aSjb150015 ASSERT(sr->session); 1424faa1795aSjb150015 ASSERT(sr->r_xa == NULL); 1425faa1795aSjb150015 1426cb174861Sjoyce mcintosh if (sr->fid_ofile != NULL) { 14272c2961f8Sjose borrego smb_ofile_release(sr->fid_ofile); 1428cb174861Sjoyce mcintosh } 14292c2961f8Sjose borrego 14302c2961f8Sjose borrego if (sr->tid_tree != NULL) 1431faa1795aSjb150015 smb_tree_release(sr->tid_tree); 1432faa1795aSjb150015 14332c2961f8Sjose borrego if (sr->uid_user != NULL) 1434faa1795aSjb150015 smb_user_release(sr->uid_user); 1435faa1795aSjb150015 14361160dcf7SMatt Barden if (sr->tform_ssn != NULL) 14371160dcf7SMatt Barden smb_user_release(sr->tform_ssn); 14381160dcf7SMatt Barden 14398f70e16bSGordon Ross /* 14408f70e16bSGordon Ross * The above may have left work on the delete queues 14418f70e16bSGordon Ross */ 14428f70e16bSGordon Ross smb_llist_flush(&sr->session->s_tree_list); 14438f70e16bSGordon Ross smb_llist_flush(&sr->session->s_user_list); 14448f70e16bSGordon Ross 1445faa1795aSjb150015 smb_slist_remove(&sr->session->s_req_list, sr); 1446faa1795aSjb150015 1447faa1795aSjb150015 sr->session = NULL; 1448faa1795aSjb150015 1449bbf6f00cSJordan Brown smb_srm_fini(sr); 1450faa1795aSjb150015 1451faa1795aSjb150015 if (sr->sr_request_buf) 1452faa1795aSjb150015 kmem_free(sr->sr_request_buf, sr->sr_req_length); 1453faa1795aSjb150015 if (sr->command.chain) 1454faa1795aSjb150015 m_freem(sr->command.chain); 1455faa1795aSjb150015 if (sr->reply.chain) 1456faa1795aSjb150015 m_freem(sr->reply.chain); 1457faa1795aSjb150015 if (sr->raw_data.chain) 1458faa1795aSjb150015 m_freem(sr->raw_data.chain); 1459faa1795aSjb150015 1460faa1795aSjb150015 sr->sr_magic = 0; 1461faa1795aSjb150015 mutex_destroy(&sr->sr_mutex); 14628622ec45SGordon Ross kmem_cache_free(smb_cache_request, sr); 1463da6c28aaSamw } 14647f667e74Sjose borrego 14652c2961f8Sjose borrego boolean_t 14662c2961f8Sjose borrego smb_session_oplocks_enable(smb_session_t *session) 14672c2961f8Sjose borrego { 14682c2961f8Sjose borrego SMB_SESSION_VALID(session); 14692c2961f8Sjose borrego if (session->s_cfg.skc_oplock_enable == 0) 14702c2961f8Sjose borrego return (B_FALSE); 14712c2961f8Sjose borrego else 14722c2961f8Sjose borrego return (B_TRUE); 14732c2961f8Sjose borrego } 14742c2961f8Sjose borrego 1475cb174861Sjoyce mcintosh boolean_t 1476cb174861Sjoyce mcintosh smb_session_levelII_oplocks(smb_session_t *session) 1477cb174861Sjoyce mcintosh { 1478cb174861Sjoyce mcintosh SMB_SESSION_VALID(session); 1479a90cf9f2SGordon Ross 1480a90cf9f2SGordon Ross /* Older clients only do Level II oplocks if negotiated. */ 1481a90cf9f2SGordon Ross if ((session->capabilities & CAP_LEVEL_II_OPLOCKS) != 0) 1482a90cf9f2SGordon Ross return (B_TRUE); 1483a90cf9f2SGordon Ross 1484a90cf9f2SGordon Ross return (B_FALSE); 1485cb174861Sjoyce mcintosh } 1486cb174861Sjoyce mcintosh 1487f9bc6dadSDmitry.Savitsky@nexenta.com static void 1488f9bc6dadSDmitry.Savitsky@nexenta.com smb_session_genkey(smb_session_t *session) 1489f9bc6dadSDmitry.Savitsky@nexenta.com { 1490f9bc6dadSDmitry.Savitsky@nexenta.com uint8_t tmp_key[SMB_CHALLENGE_SZ]; 1491f9bc6dadSDmitry.Savitsky@nexenta.com 1492f9bc6dadSDmitry.Savitsky@nexenta.com (void) random_get_pseudo_bytes(tmp_key, SMB_CHALLENGE_SZ); 1493f9bc6dadSDmitry.Savitsky@nexenta.com bcopy(tmp_key, &session->challenge_key, SMB_CHALLENGE_SZ); 1494f9bc6dadSDmitry.Savitsky@nexenta.com session->challenge_len = SMB_CHALLENGE_SZ; 1495f9bc6dadSDmitry.Savitsky@nexenta.com 1496f9bc6dadSDmitry.Savitsky@nexenta.com (void) random_get_pseudo_bytes(tmp_key, 4); 1497f9bc6dadSDmitry.Savitsky@nexenta.com session->sesskey = tmp_key[0] | tmp_key[1] << 8 | 1498f9bc6dadSDmitry.Savitsky@nexenta.com tmp_key[2] << 16 | tmp_key[3] << 24; 1499f9bc6dadSDmitry.Savitsky@nexenta.com } 1500