smb_session.c revision 08f0d8da054d72c87f9a35f2ea891d2c3541ceb5
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/socketvar.h>
#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_i18n.h>
static void smb_session_cancel(smb_session_t *);
static int smb_session_message(smb_session_t *);
void
{
while (session) {
/*
* Walk through the table and decrement each keep_alive
* timer that has not timed out yet. (keepalive > 0)
*/
if (session->keep_alive &&
session->keep_alive--;
}
}
void
{
if (new_keep_alive == smb_keep_alive)
return;
/*
* keep alive == 0 means do not drop connection if it's idle
*/
/*
* Walk through the table and set each session to the new keep_alive
* value if they have not already timed out. Block clock interrupts.
*/
while (sn) {
}
while (sn) {
if (sn->keep_alive)
}
}
/*
* smb_reconnection_check
*
* This function is called when a client indicates its current connection
* should be the only one it has with the server, as indicated by VC=0 in
* a SessionSetupX request. We go through the session list and destroy any
* stale connections for that client.
*
* Clients don't associate IP addresses and servers. So a client may make
* independent connections (i.e. with VC=0) to a server with multiple
* IP addresses. So, when checking for a reconnection, we need to include
* the local IP address, to which the client is connecting, when checking
* for stale sessions.
*
* Also check the server's NetBIOS name to support simultaneous access by
* multiple clients behind a NAT server. This will only work for SMB over
* NetBIOS on TCP port 139, it will not work SMB over TCP port 445 because
* there is no NetBIOS name. See also Knowledge Base article Q301673.
*/
void
{
while (sn) {
}
}
}
/*
* Send a session message - supports SMB-over-NBT and SMB-over-TCP.
*
* The mbuf chain is copied into a contiguous buffer so that the whole
* message is submitted to smb_sosend as a single request. This should
* TCP_NODELAY has been set on the socket.
*
* If an mbuf chain is provided, it will be freed and set to NULL here.
*/
int
{
int rc;
}
return (ENOTCONN);
default:
break;
}
txr = smb_net_txr_alloc();
if (rc != 0) {
return (rc);
}
}
if (rc != 0) {
return (rc);
}
}
/*
* Read, process and respond to a NetBIOS session request.
*
* A NetBIOS session must be established for SMB-over-NetBIOS. Validate
* the calling and called name format and save the client NetBIOS name,
* which is used when a NetBIOS session is established to check for and
* cleanup leftover state from a previous session.
*
* Session requests are not valid for SMB-over-TCP, which is unfortunate
* because without the client name leftover state cannot be cleaned up
* if the client is behind a NAT server.
*/
static int
{
int rc;
char *calling_name;
char *called_name;
char client_name[NETBIOS_NAME_SZ];
struct mbuf_chain mbc;
char *p;
unsigned int cpid = oem_get_smb_cpid();
return (rc);
smb_xprt_t *, &hdr);
return (EINVAL);
}
return (rc);
}
called_name = &names[0];
&mbc);
return (EINVAL);
}
char *, calling_name, char *, client_name);
/*
* The client NetBIOS name is in oem codepage format.
* We need to convert it to unicode and store it in
* multi-byte format. We also need to strip off any
* spaces added as part of the NetBIOS name encoding.
*/
*p = '\0';
}
/*
* Read 4-byte header from the session socket and build an in-memory
* session transport header. See smb_xprt_t definition for header
* format information.
*
* Direct hosted NetBIOS-less SMB (SMB-over-TCP) uses port 445. The
* first byte of the four-byte header must be 0 and the next three
* bytes contain the length of the remaining data.
*/
int
{
int rc;
unsigned char buf[NETBIOS_HDR_SZ];
return (rc);
switch (session->s_local_port) {
case SSN_SRVC_TCP_PORT:
break;
case SMB_SRVC_TCP_PORT:
return (EPROTO);
}
break;
default:
return (EPROTO);
}
return (0);
}
/*
* Encode a transport session packet header into a 4-byte buffer.
* See smb_xprt_t definition for header format information.
*/
static int
{
return (-1);
}
switch (session->s_local_port) {
case SSN_SRVC_TCP_PORT:
break;
case SMB_SRVC_TCP_PORT:
break;
default:
return (-1);
}
return (0);
}
static void
{
/*
* Setup mbuf, mimic MCLGET but use the complete packet buffer.
*/
/*
* Initialize the rest of the mbuf_chain fields
*/
}
/*
* smb_request_cancel
*
* Handle a cancel for a request properly depending on the current request
* state.
*/
void
{
case SMB_REQ_STATE_SUBMITTED:
case SMB_REQ_STATE_ACTIVE:
case SMB_REQ_STATE_CLEANED_UP:
break;
/*
* This request is waiting on a lock. Wakeup everything
* waiting on the lock so that the relevant thread regains
* control and notices that is has been canceled. The
* other lock request threads waiting on this lock will go
* back to sleep when they discover they are still blocked.
*/
break;
/*
* Cancellations for these states are handled by the
* notify-change code
*/
break;
case SMB_REQ_STATE_COMPLETED:
case SMB_REQ_STATE_CANCELED:
/*
* No action required for these states since the request
* is completing.
*/
break;
/*
* Cases included:
* SMB_REQ_STATE_FREE:
* SMB_REQ_STATE_INITIALIZING:
*/
default:
SMB_PANIC();
}
}
/*
* This is the entry point for processing SMB messages over NetBIOS or
* SMB-over-TCP.
*
* NetBIOS connections require a session request to establish a session
* on which to send session messages.
*
* Session requests are not valid on SMB-over-TCP. We don't need to do
* anything here as session requests will be treated as an error when
* handling session messages.
*/
int
{
int rc = 0;
return (EINVAL);
if (rc) {
return (rc);
}
}
/*
* At this point everything related to the session should have been
* cleaned up and we expect that nothing will attempt to use the
* socket.
*/
return (rc);
}
/*
* Read and process SMB requests.
*
* Returns:
* 0 Success
* 1 Unable to read transport header
* 2 Invalid transport header type
* 3 Invalid SMB length (too small)
* 4 Unable to read SMB header
* 5 Invalid SMB header (bad magic number)
* 6 Unable to read SMB data
* 2x Write raw failed
*/
static int
{
int rc;
for (;;) {
if (rc)
return (rc);
smb_xprt_t *, &hdr);
/*
* Anything other than SESSION_MESSAGE or
* SESSION_KEEP_ALIVE is an error. A SESSION_REQUEST
* may indicate a new session request but we need to
* close this session and we can treat it as an error
* here.
*/
continue;
}
return (EPROTO);
}
return (EPROTO);
/*
* Allocate a request context, read the SMB header and validate
* it. The sr includes a buffer large enough to hold the SMB
* request payload. If the header looks valid, read any
* remaining data.
*/
if (rc) {
return (rc);
}
if (SMB_PROTOCOL_MAGIC_INVALID(sr)) {
return (EPROTO);
}
if (resid > SMB_HEADER_LEN) {
resid -= SMB_HEADER_LEN;
if (rc) {
return (rc);
}
}
/*
* Initialize command MBC to represent the received data.
*/
/*
* If this is a raw write, hand off the request. The handler
* will retrieve the remaining raw data and process the request.
*/
if (SMB_IS_WRITERAW(sr)) {
/* XXX smb_request_free(sr); ??? */
return (rc);
}
}
}
/*
* Port will be SSN_SRVC_TCP_PORT or SMB_SRVC_TCP_PORT.
*/
int family)
{
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
return (NULL);
}
if (new_so) {
(void) ksocket_getsockname(new_so,
sizeof (in_addr_t));
(void) ksocket_getpeername(new_so,
sizeof (in_addr_t));
} else {
(void) ksocket_getsockname(new_so,
sizeof (in6_addr_t));
(void) ksocket_getpeername(new_so,
sizeof (in6_addr_t));
}
}
return (session);
}
void
{
}
}
static void
{
/* All the request currently being treated must be canceled. */
/*
* We wait for the completion of all the requests associated with
* this session.
*/
/*
* At this point the reference count of the users, trees, files,
* directories should be zero. It should be possible to destroy them
* without any problem.
*/
while (xa) {
}
}
/*
* Cancel requests. If a non-null tree is specified, only requests specific
* to that tree will be cancelled. If a non-null sr is specified, that sr
* will be not be cancelled - this would typically be the caller's sr.
*/
void
{
while (sr) {
if ((sr != exclude_sr) &&
}
}
void
smb_session_worker(void *arg)
{
case SMB_REQ_STATE_SUBMITTED:
if (smb_dispatch_request(sr)) {
}
break;
default:
break;
}
}
/*
* smb_session_disconnect_share
*
* Disconnects the specified share. This function should be called after the
* share passed in has been made unavailable by the "share manager".
*/
void
{
while (session) {
while (user) {
}
break;
}
default:
break;
}
}
}
void
{
}
void
{
}
void
{
}
void
{
if (session) {
return;
}
}
{
if (session) {
}
return (session);
}
void
{
}
/*
* smb_session_list_signal
*
* This function signals all the session threads. The intent is to terminate
* them. The sessions still in the SMB_SESSION_STATE_INITIALIZED are delete
* immediately.
*
* This function must only be called by the threads listening and accepting
* connections. They must pass in their respective session list.
*/
void
{
}
while (session) {
}
}
/*
* smb_session_lookup_user
*/
static smb_user_t *
{
while (user) {
break;
}
}
}
return (user);
}
/*
* If a user attempts to log in subsequently from the specified session,
* duplicates the existing SMB user instance such that all SMB user
* instances that corresponds to the same user on the given session
* reference the same user's cred.
*
* Returns NULL if the given user hasn't yet logged in from this
* specified session. Otherwise, returns a user instance that corresponds
* to this subsequent login.
*/
{
if (orig_user) {
}
return (user);
}
/*
* smb_request_alloc
*
* Allocate an smb_request_t structure from the kmem_cache. Partially
*
* Returns pointer to a request
*/
{
/*
* Future: Use constructor to pre-initialize some fields. For now
* there are so many fields that it is easiest just to zero the
* whole thing and start over.
*/
if (req_length)
return (sr);
}
/*
* smb_request_free
*
* release the memories which have been allocated for a smb request.
*/
void
{
/* Release any temp storage */
if (sr->sr_request_buf)
}
void
{
char ipstr[INET6_ADDRSTRLEN];
else
}
{
return (B_FALSE);
else
return (B_TRUE);
}
/*
* smb_session_breaking_oplock
*
* This MUST be a cross-session call, i.e. the caller must be in a different
* context than the one passed. The mutex of the SMB node requiring an oplock
* break MUST be dropped before calling this function. This last requirement is
* due to a potential deadlock that can occur when trying to enter the lock of
* the session passed in.
*/
void
{
0xFFFF, 0, 0xFFFF, 8, 0xFF,
break;
break;
break;
default:
SMB_PANIC();
}
}