smbrdr_session.c revision 8d7e41661dc4633488e93b13363137523ce59977
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This module provides the netbios and SMB negotiation, connect and
* disconnect interface.
*/
#include <unistd.h>
#include <syslog.h>
#include <synch.h>
#include <string.h>
#include <strings.h>
#include <pthread.h>
#include <errno.h>
#include <inttypes.h>
#include <netdb.h>
#include <smbsrv/libsmbrdr.h>
#include <smbsrv/ntstatus.h>
#include <smbsrv/libmlsvc.h>
#include <smbrdr.h>
#include <smbrdr_ipc_util.h>
static uint16_t smbrdr_ports[] = {
};
static mutex_t smbrdr_screate_mtx;
static uint32_t session_id = 0;
static struct sdb_session *smbrdr_session_init(char *, char *);
static int smbrdr_session_connect(char *, char *);
static int smbrdr_smb_negotiate(struct sdb_session *);
static int smbrdr_echo(struct sdb_session *);
static void smbrdr_session_disconnect(struct sdb_session *, int);
static void
{
}
/*
* Entry pointy for smbrdr initialization.
*/
void
smbrdr_init(void)
{
}
/*
* mlsvc_disconnect
*
* Disconnects the session with given server.
*/
void
mlsvc_disconnect(char *server)
{
struct sdb_session *session;
if (session) {
}
}
/*
* smbrdr_negotiate
*
* Negotiate a session with a domain controller in the specified domain.
* The domain must be one of values from the smbinfo that indicates the
* resource domain or the account domain.
*
* If a session already exists, we can use that one. Otherwise we create
* a new one. This sets up the session key and session security info that
* we'll need later to authenticate the user. The session security info
* is returned to support the SMB client pass-through authentication
* interface.
*
* Returns 0 on success, otherwise -1.
*/
/*ARGSUSED*/
int
{
struct sdb_session *session = 0;
int rc;
/*
* The mutex is to make session lookup and create atomic
* so we don't end up with two sessions with the same
* server.
*/
(void) mutex_lock(&smbrdr_screate_mtx);
if (session != 0) {
/* session is good, use it */
rc = 0;
goto done;
} else {
/* stale session */
}
}
done:
(void) mutex_unlock(&smbrdr_screate_mtx);
if (rc != 0)
return (rc);
}
/*
* smbrdr_session_connect
*
* This is the entry point for establishing an SMB connection to a
* domain controller. A session structure is allocated, a netbios
* session is set up and the SMB protocol is negotiated. If this is
* successful, the returned session structure can be used to logon
* to the the domain. A null pointer is returned if the connect fails.
*/
static int
{
struct sdb_session *session;
int rc = 0;
/*
* smbrdr_session_init() will lock the session so that it wouldn't
* be accessible until it's established otherwise another thread
* might get access to a session which is not fully established.
*/
== NULL) {
return (-1);
}
smbrdr_ports[port]);
if (rc == 0) {
smbrdr_ports[port]);
break;
}
}
if (rc < 0) {
return (-1);
}
if (smbrdr_smb_negotiate(session) < 0) {
return (-1);
}
return (0);
}
/*
* smbrdr_trnsprt_connect
*
* standard socket sutff. The paranoia check for socket descriptor 0
* is because we had a problem with this value and the console telnet
*
* Return 0 on success. Otherwise return (-1) to indicate a problem.
*/
static int
{
char hostname[MAXHOSTNAMELEN];
struct sockaddr_in sin;
char server_name[SMB_PI_MAX_DOMAIN];
unsigned int cpid = oem_get_smb_cpid();
return (-1);
}
if (sock != 0)
return (-1);
}
if (rc == 0) {
if (sock != 0)
return (-1);
}
/*
* If we are using NetBIOS, we need to set up a NETBIOS session.
* This typically implies that we will be using port 139.
* Otherwise, we're doing NetBIOS-less SMB, i.e. SMB over TCP,
* which is typically on port 445.
*/
if (port == SSN_SRVC_TCP_PORT) {
if (sock != 0)
return (-1);
}
if (rc != 0) {
"smbrdr: NBT session request to %s failed %d",
server_name, rc);
if (sock != 0)
return (-1);
}
}
return (0);
}
/*
* smbrdr_smb_negotiate
*
* Negotiate the protocol we are going to use as described in CIFS
* section 4.1.1. The only protocol we support is NT LM 0.12, so we
* really expect to see dialect 0 in the response. The only other
* data gathered is the session key.
*
* Negotiate using ASCII strings.
*
* Return 0 on success. Otherwise return a -ve error code.
*/
static int
{
unsigned short dialect;
int rc;
if (status != NT_STATUS_SUCCESS)
return (-1);
if (rc <= 0) {
return (-1);
}
if (status != NT_STATUS_SUCCESS) {
return (-1);
}
sess->challenge_len = 0;
"1.(dialect)w(mode)b12.(key)l(cap)l10.(keylen)b2.",
&tmp_clen);
return (-1);
}
if (rc <= 0) {
return (-1);
}
}
return (0);
}
/*
* smbrdr_session_init
*
* Allocate an available slot in session table for the specified domain
* information.
*
* IMPORTANT! the returned session will be locked caller has to unlock
* it by calling smbrdr_session_unlock() after it's done with
* the pointer.
*/
static struct sdb_session *
{
int i, rc;
struct hostent *h;
return (NULL);
return (NULL);
}
freehostent(h);
for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) {
session = &session_table[i];
"Solaris", SMB_PI_MAX_NATIVE_OS);
"Windows NT 4.0", SMB_PI_MAX_LANMAN);
/*
* Note that by sending vc=0 server will shutdown all
* the other connections with NAS if there is any.
*/
return (session);
}
}
return (NULL);
}
/*
* smbrdr_session_disconnect
*
* This is the entry point for disconnecting an SMB connection. Ensure
* that all logons and shares associated with this session are
* terminated and then free the session.
*
* if 'cleanup' is 1 it means that only sessions that are not active
* should be cleaned up. if 'cleanup' is 0 disconnect the session in any
* states.
*/
static void
{
int state;
return;
if ((state != SDB_SSTATE_DISCONNECTING) &&
(state != SDB_SSTATE_CLEANING) &&
(state != SDB_SSTATE_START)) {
/*
* if session is in stale state it means the connection
* is lost so no logoff, tdcon, or close can actually
* be sent, thus only cleanup our side.
*/
}
}
}
/*
* smbrdr_session_unlock
*
* Unlock given session structure.
*/
void
{
if (session)
}
/*
* smbrdr_session_lock
*
* Lookup the session associated with the specified domain controller.
* If a match is found, we return a pointer to the session, Otherwise
* we return null. Only sessions in "negotiated" state are checked.
* This mechanism is very simple and implies that we
* should only ever have one session open to any domain controller.
*
* IMPORTANT! the returned session will be locked caller has to unlock
* it by calling smbrdr_session_unlock() after it's done with
* the pointer.
*/
struct sdb_session *
{
struct sdb_session *session;
int i;
return (NULL);
for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) {
session = &session_table[i];
if (username) {
if (strcasecmp(username,
return (session);
return (NULL);
}
return (session);
}
}
return (NULL);
}
/*
* smbrdr_session_info
*
* Return session information related to the specified
* named pipe (fid).
*/
int
{
struct sdb_session *session;
struct sdb_netuse *netuse;
return (-1);
"smbrdr_session_info: unknown file (%d)", fid);
return (-1);
}
return (0);
}
/*
* smbrdr_dump_sessions
*
* Debug function to dump the session table.
*/
void
smbrdr_dump_sessions(void)
{
struct sdb_session *session;
char ipstr[16];
int i;
for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) {
session = &session_table[i];
(const void *)(&session->srv_ipaddr),
}
}
}
/*
* mlsvc_echo
*/
int
mlsvc_echo(char *server)
{
struct sdb_session *session;
int res = 0;
return (1);
if (smbrdr_echo(session) != 0) {
res = -1;
}
return (res);
}
/*
* smbrdr_echo
*
* This request can be used to test the connection to the server. The
* server should echo the data sent. The server should ignore the tid
* in the header, so this request when there are no tree connections.
* See CIFS/1.0 section 4.1.7.
*
* Return 0 on success. Otherwise return a -ve error code.
*/
static int
{
static char *echo_str = "smbrdr";
int rc;
return (-1);
}
if (status != NT_STATUS_SUCCESS)
return (-1);
if (rc <= 0) {
return (-1);
}
if (status != NT_STATUS_SUCCESS)
return (-1);
return (0);
}