Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1004 lines
42 KiB

/****************************************************************************/
// sdqueryrpcfn.cpp
//
// TS Session Directory Query RPC server-side implementations.
//
// Copyright (C) 2000, Microsoft Corporation
/****************************************************************************/
#include "dis.h"
#include "tssdshrd.h"
#include "jetrpc.h"
#include "jetsdis.h"
#include "sdevent.h"
#pragma warning (push, 4)
#define TSSD_SERACH_MAX_RECORD 0xFFFFFFFF
#define TSSD_NameLength 128
extern PSID g_pAdminSid;
/****************************************************************************/
// SDQueryRPCAccessCheck
//
// Check if this SD Query RPC caller havs access right or not
// Access is given only to administrator using ncalrpc protocol
/****************************************************************************/
RPC_STATUS RPC_ENTRY SDQueryRPCAccessCheck(RPC_IF_HANDLE idIF, void *Binding)
{
RPC_STATUS rpcStatus, rc;
HANDLE hClientToken = NULL;
DWORD Error;
BOOL AccessStatus = FALSE;
//RPC_AUTHZ_HANDLE hPrivs;
//DWORD dwAuthn;
idIF;
if (NULL == g_pAdminSid) {
goto HandleError;
}
// Check if the client uses the protocol sequence we expect
if (!CheckRPCClientProtoSeq(Binding, L"ncalrpc")) {
TSDISErrorOut(L"In SDQueryRPCAccessCheck: Client doesn't use the ncalrpc protocol sequence %u\n");
goto HandleError;
}
// Check the access right of this rpc call
rpcStatus = RpcImpersonateClient(Binding);
if (RPC_S_OK != rpcStatus) {
TSDISErrorOut(L"In SDQueryRPCAccessCheck: RpcImpersonateClient fail with %u\n", rpcStatus);
goto HandleError;
}
// get our impersonated token
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hClientToken)) {
Error = GetLastError();
TSDISErrorOut(L"In SDQueryRPCAccessCheck: OpenThreadToken Error %u\n", Error);
RpcRevertToSelf();
goto HandleError;
}
RpcRevertToSelf();
if (!CheckTokenMembership(hClientToken,
g_pAdminSid,
&AccessStatus)) {
AccessStatus = FALSE;
Error = GetLastError();
TSDISErrorOut(L"In SDQueryRPCAccessCheck: CheckTokenMembership fails with %u\n", Error);
}
HandleError:
if (AccessStatus) {
rc = RPC_S_OK;
}
else {
TSDISErrorOut(L"In SDQueryRPCAccessCheck: Unauthorized LPC call\n");
rc = ERROR_ACCESS_DENIED;
}
if (hClientToken != NULL) {
CloseHandle(hClientToken);
}
return rc;
}
// Query sessions for a username/domainname
DWORD TSSDRpcQuerySessionInfoByUserName(
/* [in] */ handle_t Binding,
/* [in] */ WCHAR *UserName,
/* [in] */ WCHAR *DomainName,
/* [out] */ DWORD *pNumberOfSessions,
/* [out] */ TSSD_SessionInfo __RPC_FAR __RPC_FAR **ppSessionInfo)
{
Binding;
TSSD_SessionInfo *pSessionInfo = NULL;
DWORD rc = (DWORD) E_FAIL;
JET_SESID sesid = JET_sesidNil;
JET_TABLEID servdirtableid;
JET_TABLEID sessdirtableid;
JET_DBID dbid;
JET_ERR err;
unsigned long cbActual;
long ServerID;
DWORD i;
*pNumberOfSessions = 0;
*ppSessionInfo = NULL;
TRC1((TB,"TSSDRpcQuerySessionInfoByUserName: Query for user: %S\\%S", DomainName, UserName));
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetBeginTransaction(sesid));
// search the session table for DomainName/UserName
CALL(JetSetCurrentIndex(sesid, sessdirtableid, "AllSessionIndex"));
CALL(JetMakeKey(sesid, sessdirtableid, UserName, (unsigned)
(wcslen(UserName) + 1) * sizeof(WCHAR), JET_bitNewKey));
CALL(JetMakeKey(sesid, sessdirtableid, DomainName, (unsigned)
(wcslen(DomainName) + 1) * sizeof(WCHAR), 0));
err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange);
if (err != JET_errSuccess) {
TRC1((TB,"TSSDRpcQuerySessionInfoByUserName: Query for user: %S\\%S does not exist", DomainName, UserName));
goto HandleError;
}
CALL(JetIndexRecordCount(sesid, sessdirtableid, pNumberOfSessions, TSSD_SERACH_MAX_RECORD));
TRC1((TB, "Find %d session for this user", *pNumberOfSessions));
*ppSessionInfo = (TSSD_SessionInfo *) MIDL_user_allocate(sizeof(TSSD_SessionInfo) *
*pNumberOfSessions);
pSessionInfo = *ppSessionInfo;
if (pSessionInfo == NULL) {
ERR((TB, "TSSDRpcQuerySessionInfoByUserName: Memory alloc failed!\n"));
goto HandleError;
}
// retrieve the info for Sessions
CALL(JetMove(sesid, sessdirtableid, JET_MoveFirst, 0));
CALL(JetMakeKey(sesid, sessdirtableid, UserName, (unsigned)
(wcslen(UserName) + 1) * sizeof(WCHAR), JET_bitNewKey));
CALL(JetMakeKey(sesid, sessdirtableid, DomainName, (unsigned)
(wcslen(DomainName) + 1) * sizeof(WCHAR), 0));
CALL(JetSeek(sesid, sessdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange));
for (i=0; i<*pNumberOfSessions; i++) {
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_SERVERID_INTERNAL_INDEX], &ServerID,
sizeof(ServerID), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_USERNAME_INTERNAL_INDEX], pSessionInfo[i].UserName,
sizeof(pSessionInfo[i].UserName), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_DOMAIN_INTERNAL_INDEX], pSessionInfo[i].DomainName,
sizeof(pSessionInfo[i].DomainName), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_SESSIONID_INTERNAL_INDEX], &(pSessionInfo[i].SessionID),
sizeof(pSessionInfo[i].SessionID), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_TSPROTOCOL_INTERNAL_INDEX], &(pSessionInfo[i].TSProtocol),
sizeof(pSessionInfo[i].TSProtocol), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_APPTYPE_INTERNAL_INDEX], pSessionInfo[i].ApplicationType,
sizeof(pSessionInfo[i].ApplicationType), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_RESWIDTH_INTERNAL_INDEX], &(pSessionInfo[i].ResolutionWidth),
sizeof(pSessionInfo[i].ResolutionWidth), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_RESHEIGHT_INTERNAL_INDEX], &(pSessionInfo[i].ResolutionHeight),
sizeof(pSessionInfo[i].ResolutionHeight), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_COLORDEPTH_INTERNAL_INDEX], &(pSessionInfo[i].ColorDepth),
sizeof(pSessionInfo[i].ColorDepth), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_STATE_INTERNAL_INDEX], &(pSessionInfo[i].SessionState),
sizeof(pSessionInfo[i].SessionState), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_CTLOW_INTERNAL_INDEX], &(pSessionInfo[i].CreateTime.dwLowDateTime),
sizeof(pSessionInfo[i].CreateTime.dwLowDateTime), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_CTHIGH_INTERNAL_INDEX], &(pSessionInfo[i].CreateTime.dwHighDateTime),
sizeof(pSessionInfo[i].CreateTime.dwHighDateTime), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_DTLOW_INTERNAL_INDEX], &(pSessionInfo[i].DisconnectTime.dwLowDateTime),
sizeof(pSessionInfo[i].DisconnectTime.dwLowDateTime), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_DTHIGH_INTERNAL_INDEX], &(pSessionInfo[i].DisconnectTime.dwHighDateTime),
sizeof(pSessionInfo[i].DisconnectTime.dwHighDateTime), &cbActual, 0, NULL));
// Find the cluster name the server belongs to
CALL(JetMove(sesid, servdirtableid, JET_MoveFirst, 0));
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
CALL(JetMakeKey(sesid, servdirtableid, (const void *)&ServerID, sizeof(ServerID),
JET_bitNewKey));
CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVDNSNAME_INTERNAL_INDEX], pSessionInfo[i].ServerName,
sizeof(pSessionInfo[i].ServerName), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVADDR_INTERNAL_INDEX], pSessionInfo[i].ServerIPAddress,
sizeof(pSessionInfo[i].ServerIPAddress), &cbActual, 0, NULL));
if (i != *pNumberOfSessions -1) {
CALL(JetMove(sesid, sessdirtableid, JET_MoveNext, 0));
}
}
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseTable(sesid, sessdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
rc = (DWORD)RPC_S_OK;
HandleError:
if ((sesid != JET_sesidNil) && (rc != 0)) {
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
return rc;
}
// Query for all sessions on a server
DWORD TSSDRpcQuerySessionInfoByServer(
/* [in] */ handle_t Binding,
/* [in] */ WCHAR *ServerName,
/* [out] */ DWORD *pNumberOfSessions,
/* [out] */ TSSD_SessionInfo __RPC_FAR __RPC_FAR **ppSessionInfo)
{
Binding;
TSSD_SessionInfo *pSessionInfo = NULL;
DWORD rc = (DWORD) E_FAIL;
JET_SESID sesid = JET_sesidNil;
JET_TABLEID servdirtableid;
JET_TABLEID sessdirtableid;
JET_DBID dbid;
JET_ERR err;
unsigned long cbActual;
long ServerID;
WCHAR ServerIPAddress[TSSD_NameLength];
DWORD i;
*pNumberOfSessions = 0;
*ppSessionInfo = NULL;
TRC1((TB,"TSSDRpcQuerySessionInfoByServer: Query for servername %S", ServerName));
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetBeginTransaction(sesid));
// search the server table by the ServerName for SeverID
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServDNSNameIndex"));
CALL(JetMakeKey(sesid, servdirtableid, ServerName, (unsigned)
(wcslen(ServerName) + 1) * sizeof(WCHAR), JET_bitNewKey));
err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ);
if (err != JET_errSuccess) {
TRC1((TB,"TSSDRpcQuerySessionInfoByServer: Query for servername: %S does not exist", ServerName));
goto HandleError;
}
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVID_INTERNAL_INDEX], &ServerID,
sizeof(ServerID), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVADDR_INTERNAL_INDEX], ServerIPAddress,
sizeof(ServerIPAddress), &cbActual, 0, NULL));
// search the sessions by this ServerID
CALL(JetSetCurrentIndex(sesid, sessdirtableid, "ServerIndex"));
CALL(JetMakeKey(sesid, sessdirtableid, &ServerID, sizeof(ServerID), JET_bitNewKey));
err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange);
if (err != JET_errSuccess) {
TRC1((TB,"TSSDRpcQuerySessionInfoByServer: Query for servername: %S does not have any session", ServerName));
goto HandleError;
}
CALL(JetIndexRecordCount(sesid, sessdirtableid, pNumberOfSessions, TSSD_SERACH_MAX_RECORD));
TRC1((TB, "Find %d session for this user", *pNumberOfSessions));
*ppSessionInfo = (TSSD_SessionInfo *) MIDL_user_allocate(sizeof(TSSD_SessionInfo) *
*pNumberOfSessions);
pSessionInfo = *ppSessionInfo;
if (pSessionInfo == NULL) {
ERR((TB, "TSSDRpcQuerySessionInfoByServer: Memory alloc failed!\n"));
goto HandleError;
}
// retrieve the info for Sessions
CALL(JetMove(sesid, sessdirtableid, JET_MoveFirst, 0));
CALL(JetSetCurrentIndex(sesid, sessdirtableid, "ServerIndex"));
CALL(JetMakeKey(sesid, sessdirtableid, &ServerID, sizeof(ServerID), JET_bitNewKey));
CALL(JetSeek(sesid, sessdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange));
for (i=0; i<*pNumberOfSessions; i++) {
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_SERVERID_INTERNAL_INDEX], &ServerID,
sizeof(ServerID), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_USERNAME_INTERNAL_INDEX], pSessionInfo[i].UserName,
sizeof(pSessionInfo[i].UserName), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_DOMAIN_INTERNAL_INDEX], pSessionInfo[i].DomainName,
sizeof(pSessionInfo[i].DomainName), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_SESSIONID_INTERNAL_INDEX], &(pSessionInfo[i].SessionID),
sizeof(pSessionInfo[i].SessionID), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_TSPROTOCOL_INTERNAL_INDEX], &(pSessionInfo[i].TSProtocol),
sizeof(pSessionInfo[i].TSProtocol), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_APPTYPE_INTERNAL_INDEX], pSessionInfo[i].ApplicationType,
sizeof(pSessionInfo[i].ApplicationType), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_RESWIDTH_INTERNAL_INDEX], &(pSessionInfo[i].ResolutionWidth),
sizeof(pSessionInfo[i].ResolutionWidth), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_RESHEIGHT_INTERNAL_INDEX], &(pSessionInfo[i].ResolutionHeight),
sizeof(pSessionInfo[i].ResolutionHeight), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_COLORDEPTH_INTERNAL_INDEX], &(pSessionInfo[i].ColorDepth),
sizeof(pSessionInfo[i].ColorDepth), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_STATE_INTERNAL_INDEX], &(pSessionInfo[i].SessionState),
sizeof(pSessionInfo[i].SessionState), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_CTLOW_INTERNAL_INDEX], &(pSessionInfo[i].CreateTime.dwLowDateTime),
sizeof(pSessionInfo[i].CreateTime.dwLowDateTime), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_CTHIGH_INTERNAL_INDEX], &(pSessionInfo[i].CreateTime.dwHighDateTime),
sizeof(pSessionInfo[i].CreateTime.dwHighDateTime), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_DTLOW_INTERNAL_INDEX], &(pSessionInfo[i].DisconnectTime.dwLowDateTime),
sizeof(pSessionInfo[i].DisconnectTime.dwLowDateTime), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_DTHIGH_INTERNAL_INDEX], &(pSessionInfo[i].DisconnectTime.dwHighDateTime),
sizeof(pSessionInfo[i].DisconnectTime.dwHighDateTime), &cbActual, 0, NULL));
wcsncpy(pSessionInfo[i].ServerName, ServerName, TSSD_NameLength);
(pSessionInfo[i].ServerName)[TSSD_NameLength -1] = L'\0';
wcsncpy(pSessionInfo[i].ServerIPAddress, ServerIPAddress, TSSD_NameLength);
(pSessionInfo[i].ServerIPAddress)[TSSD_NameLength -1] = L'\0';
if (i != *pNumberOfSessions -1) {
CALL(JetMove(sesid, sessdirtableid, JET_MoveNext, 0));
}
}
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseTable(sesid, sessdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
rc = (DWORD)RPC_S_OK;
HandleError:
if ((sesid != JET_sesidNil) && (rc != 0)) {
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
return rc;
}
// Query the server info by server name
DWORD TSSDRpcQueryServerByName(
/* [in] */ handle_t Binding,
/* [in] */ WCHAR *ServerName,
/* [out] */ DWORD *pNumberOfServers,
/* [out] */ TSSD_ServerInfo __RPC_FAR __RPC_FAR **ppServerInfo)
{
Binding;
TSSD_ServerInfo *pServerInfo;
DWORD rc = (DWORD) E_FAIL;
JET_SESID sesid = JET_sesidNil;
JET_TABLEID clusdirtableid;
JET_TABLEID servdirtableid;
JET_TABLEID sessdirtableid;
JET_DBID dbid;
JET_ERR err;
unsigned long cbActual;
long ServerID, ClusterID;
*pNumberOfServers = 0;
*ppServerInfo = NULL;
pServerInfo = NULL;
TRC1((TB,"TSSDRpcQueryServerByName: Query for Server Name: %S", ServerName));
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
&clusdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetBeginTransaction(sesid));
// search the server table for ServerName
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServDNSNameIndex"));
CALL(JetMakeKey(sesid, servdirtableid, ServerName, (unsigned)
(wcslen(ServerName) + 1) * sizeof(WCHAR), JET_bitNewKey));
err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ);
if (err != JET_errSuccess) {
TRC1((TB,"TSSDRpcQueryServerByName: Query for servername: %S does not exist", ServerName));
goto HandleError;
}
*pNumberOfServers = 1;
*ppServerInfo = (TSSD_ServerInfo *) MIDL_user_allocate(sizeof(TSSD_ServerInfo) *
*pNumberOfServers);
pServerInfo = *ppServerInfo;
if (pServerInfo == NULL) {
ERR((TB, "TSSDRpcQueryServerByName: Memory alloc failed!\n"));
goto HandleError;
}
// retrive the info for ServerInfo
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVID_INTERNAL_INDEX], &ServerID,
sizeof(ServerID), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_CLUSID_INTERNAL_INDEX], &ClusterID,
sizeof(ClusterID), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVDNSNAME_INTERNAL_INDEX], pServerInfo->ServerName,
sizeof(pServerInfo->ServerName), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVADDR_INTERNAL_INDEX], pServerInfo->ServerIPAddress,
sizeof(pServerInfo->ServerIPAddress), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SINGLESESS_INTERNAL_INDEX], &(pServerInfo->SingleSessionMode),
sizeof(pServerInfo->SingleSessionMode), &cbActual, 0, NULL));
// Find the session numbers in this server
CALL(JetMove(sesid, sessdirtableid, JET_MoveFirst, 0));
CALL(JetSetCurrentIndex(sesid, sessdirtableid, "ServerIndex"));
CALL(JetMakeKey(sesid, sessdirtableid, (const void *)&ServerID, sizeof(ServerID),
JET_bitNewKey));
err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange);
if (JET_errSuccess == err) {
CALL(JetIndexRecordCount(sesid, sessdirtableid, &(pServerInfo->NumberOfSessions), TSSD_SERACH_MAX_RECORD));
}
else {
// This server doesn't have any session
pServerInfo->NumberOfSessions = 0;
}
TRC1((TB,"TSSDRpcQueryServerByName: Get SessionNum is %d", pServerInfo->NumberOfSessions));
// Find the cluster name the server belongs to
CALL(JetMove(sesid, clusdirtableid, JET_MoveFirst, 0));
CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusIDIndex"));
CALL(JetMakeKey(sesid, clusdirtableid, (const void *)&ClusterID, sizeof(ClusterID),
JET_bitNewKey));
CALL(JetSeek(sesid, clusdirtableid, JET_bitSeekEQ));
CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_CLUSNAME_INTERNAL_INDEX], pServerInfo->ClusterName,
sizeof(pServerInfo->ClusterName), &cbActual, 0, NULL));
TRC1((TB,"TSSDRpcQueryServerByName: Get ClusterName is %S", pServerInfo->ClusterName));
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseTable(sesid, clusdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
rc = (DWORD)RPC_S_OK;
HandleError:
if ((sesid != JET_sesidNil) && (rc != 0)) {
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
return rc;
}
// Query info for all servers
DWORD TSSDRpcQueryAllServers(
/* [in] */ handle_t Binding,
/* [out] */ DWORD *pNumberOfServers,
/* [out] */ TSSD_ServerInfo __RPC_FAR __RPC_FAR **ppServerInfo)
{
Binding;
TSSD_ServerInfo *pServerInfo;
DWORD rc = (DWORD) E_FAIL;
JET_SESID sesid = JET_sesidNil;
JET_TABLEID clusdirtableid;
JET_TABLEID servdirtableid;
JET_TABLEID sessdirtableid;
JET_DBID dbid;
JET_ERR err;
unsigned long cbActual;
long ServerID, ClusterID;
DWORD i;
*pNumberOfServers = 0;
*ppServerInfo = NULL;
pServerInfo = NULL;
TRC1((TB,"TSSDRpcQueryAllServers"));
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
&clusdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetBeginTransaction(sesid));
// Get the number of servers in server table
err = JetMove(sesid, servdirtableid, JET_MoveFirst, 0);
if (err != JET_errSuccess) {
TRC1((TB,"TSSDRpcQueryAllServers: Session directory does not have any servers in it"));
goto HandleError;
}
CALL(JetIndexRecordCount(sesid, servdirtableid, pNumberOfServers, TSSD_SERACH_MAX_RECORD));
TRC1((TB, "Number of Servers found is %d", *pNumberOfServers));
*ppServerInfo = (TSSD_ServerInfo *) MIDL_user_allocate(sizeof(TSSD_ServerInfo) *
*pNumberOfServers);
pServerInfo = *ppServerInfo;
if (pServerInfo == NULL) {
ERR((TB, "TSSDRpcQueryAllServers: Memory alloc failed!\n"));
goto HandleError;
}
// Get all the servers
CALL(JetMove(sesid, servdirtableid, JET_MoveFirst, 0));
for (i=0; i<*pNumberOfServers; i++) {
// retrive the info for ServerInfo
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVID_INTERNAL_INDEX], &ServerID,
sizeof(ServerID), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_CLUSID_INTERNAL_INDEX], &ClusterID,
sizeof(ClusterID), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVDNSNAME_INTERNAL_INDEX], pServerInfo[i].ServerName,
sizeof(pServerInfo[i].ServerName), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVADDR_INTERNAL_INDEX], pServerInfo[i].ServerIPAddress,
sizeof(pServerInfo[i].ServerIPAddress), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SINGLESESS_INTERNAL_INDEX], &(pServerInfo[i].SingleSessionMode),
sizeof(pServerInfo[i].SingleSessionMode), &cbActual, 0, NULL));
// Find the session numbers in this server
err = JetMove(sesid, sessdirtableid, JET_MoveFirst, 0);
if (JET_errSuccess == err) {
CALL(JetSetCurrentIndex(sesid, sessdirtableid, "ServerIndex"));
CALL(JetMakeKey(sesid, sessdirtableid, (const void *)&ServerID, sizeof(ServerID),
JET_bitNewKey));
err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange);
if (JET_errSuccess == err) {
CALL(JetIndexRecordCount(sesid, sessdirtableid, &(pServerInfo[i].NumberOfSessions), TSSD_SERACH_MAX_RECORD));
}
else {
// This server doens't have any session
pServerInfo[i].NumberOfSessions = 0;
}
}
else {
// Session table is empty
pServerInfo[i].NumberOfSessions = 0;
}
TRC1((TB,"TSSDRpcQueryServersInCluster: Get SessionNum is %d", pServerInfo[i].NumberOfSessions));
// Find the cluster name the server belongs to
CALL(JetMove(sesid, clusdirtableid, JET_MoveFirst, 0));
CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusIDIndex"));
CALL(JetMakeKey(sesid, clusdirtableid, (const void *)&ClusterID, sizeof(ClusterID),
JET_bitNewKey));
CALL(JetSeek(sesid, clusdirtableid, JET_bitSeekEQ));
CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_CLUSNAME_INTERNAL_INDEX], pServerInfo[i].ClusterName,
sizeof(pServerInfo[i].ClusterName), &cbActual, 0, NULL));
if (i != *pNumberOfServers - 1) {
CALL(JetMove(sesid, servdirtableid, JET_MoveNext, 0));
}
}
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseTable(sesid, clusdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
rc = (DWORD)RPC_S_OK;
HandleError:
if ((sesid != JET_sesidNil) && (rc != 0)) {
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
return rc;
}
// Query all servers in the cluster by the cluster name
DWORD TSSDRpcQueryServersInCluster(
/* [in] */ handle_t Binding,
/* [in] */ WCHAR *ClusterName,
/* [out] */ DWORD *pNumberOfServers,
/* [out] */ TSSD_ServerInfo __RPC_FAR __RPC_FAR **ppServerInfo)
{
Binding;
TSSD_ServerInfo *pServerInfo;
DWORD rc = (DWORD) E_FAIL;
JET_SESID sesid = JET_sesidNil;
JET_TABLEID clusdirtableid;
JET_TABLEID servdirtableid;
JET_TABLEID sessdirtableid;
JET_DBID dbid;
JET_ERR err;
unsigned long cbActual;
long ServerID, ClusterID;
DWORD i;
*pNumberOfServers = 0;
*ppServerInfo = NULL;
pServerInfo = NULL;
TRC1((TB,"TSSDRpcQueryServersInCluster: Query for Cluster Name: %S", ClusterName));
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
&clusdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetBeginTransaction(sesid));
// search the cluster table for ClusterName
CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusNameIndex"));
CALL(JetMakeKey(sesid, clusdirtableid, ClusterName, (unsigned)
(wcslen(ClusterName) + 1) * sizeof(WCHAR), JET_bitNewKey));
err = JetSeek(sesid, clusdirtableid, JET_bitSeekEQ);
if (err != JET_errSuccess) {
TRC1((TB,"TSSDRpcQueryServersInCluster: Clustername %S does not exist", ClusterName));
goto HandleError;
}
CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_CLUSID_INTERNAL_INDEX], &ClusterID,
sizeof(ClusterID), &cbActual, 0, NULL));
// search the server table for ClusterID
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ClusterIDIndex"));
CALL(JetMakeKey(sesid, servdirtableid, &ClusterID, sizeof(ClusterID), JET_bitNewKey));
CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange));
CALL(JetIndexRecordCount(sesid, servdirtableid, pNumberOfServers, TSSD_SERACH_MAX_RECORD));
TRC1((TB, "Number of Servers found is %d", *pNumberOfServers));
*ppServerInfo = (TSSD_ServerInfo *) MIDL_user_allocate(sizeof(TSSD_ServerInfo) *
*pNumberOfServers);
pServerInfo = *ppServerInfo;
if (pServerInfo == NULL) {
ERR((TB, "TSSDRpcQueryServersInCluster: Memory alloc failed!\n"));
goto HandleError;
}
// Get all the servers for this ClusterID
CALL(JetMove(sesid, servdirtableid, JET_MoveFirst, 0));
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ClusterIDIndex"));
CALL(JetMakeKey(sesid, servdirtableid, &ClusterID, sizeof(ClusterID), JET_bitNewKey));
CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange));
for (i=0; i<*pNumberOfServers; i++) {
// retrive the info for ServerInfo
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVID_INTERNAL_INDEX], &ServerID,
sizeof(ServerID), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVDNSNAME_INTERNAL_INDEX], pServerInfo[i].ServerName,
sizeof(pServerInfo[i].ServerName), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVADDR_INTERNAL_INDEX], pServerInfo[i].ServerIPAddress,
sizeof(pServerInfo[i].ServerIPAddress), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SINGLESESS_INTERNAL_INDEX], &(pServerInfo[i].SingleSessionMode),
sizeof(pServerInfo[i].SingleSessionMode), &cbActual, 0, NULL));
wcsncpy(pServerInfo[i].ClusterName, ClusterName, TSSD_NameLength);
(pServerInfo[i].ClusterName)[TSSD_NameLength - 1] = L'\0';
// Find the session numbers for this server
err = JetMove(sesid, sessdirtableid, JET_MoveFirst, 0);
if (JET_errSuccess == err) {
CALL(JetSetCurrentIndex(sesid, sessdirtableid, "ServerIndex"));
CALL(JetMakeKey(sesid, sessdirtableid, (const void *)&ServerID, sizeof(ServerID),
JET_bitNewKey));
err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange);
if (JET_errSuccess == err) {
CALL(JetIndexRecordCount(sesid, sessdirtableid, &(pServerInfo[i].NumberOfSessions), TSSD_SERACH_MAX_RECORD));
}
else {
// This server doesn't have any sessions
pServerInfo[i].NumberOfSessions = 0;
}
TRC1((TB,"TSSDRpcQueryServersInCluster: Get SessionNum is %d", pServerInfo[i].NumberOfSessions));
}
else {
// Session table is empty
pServerInfo[i].NumberOfSessions = 0;
}
if (i != *pNumberOfServers - 1) {
CALL(JetMove(sesid, servdirtableid, JET_MoveNext, 0));
}
}
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseTable(sesid, clusdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
rc = (DWORD)RPC_S_OK;
HandleError:
if ((sesid != JET_sesidNil) && (rc != 0)) {
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
return rc;
}
// Query the info for all cluster
DWORD TSSDRpcQueryAllClusterInfo(
/* [in] */ handle_t Binding,
/* [out] */ DWORD __RPC_FAR *pNumberOfClusters,
/* [out] */ TSSD_ClusterInfo __RPC_FAR __RPC_FAR **ppClusterInfo)
{
Binding;
pNumberOfClusters;
TSSD_ClusterInfo *pClusterInfo;
DWORD rc = (DWORD) E_FAIL;
JET_SESID sesid = JET_sesidNil;
JET_TABLEID clusdirtableid;
JET_TABLEID servdirtableid;
JET_DBID dbid;
JET_ERR err;
long *pClusterID = NULL;
unsigned long cbActual;
DWORD i;
*pNumberOfClusters = 0;
pClusterInfo = NULL;
*ppClusterInfo = pClusterInfo;
TRC1((TB,"TSSDRpcQueryAllClusterInfo"));
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
&clusdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetBeginTransaction(sesid));
// ClusterName is not specified
// Get the ClusterID for all clusters
err = JetMove(sesid, clusdirtableid, JET_MoveFirst, 0);
if (err != JET_errSuccess) {
TRC1((TB,"TSSDRpcQueryAllClusterInfo: Session Directory is empty"));
goto HandleError;
}
CALL(JetIndexRecordCount(sesid, clusdirtableid, pNumberOfClusters, TSSD_SERACH_MAX_RECORD));
pClusterID = (long *)LocalAlloc(LMEM_FIXED, *pNumberOfClusters * sizeof(long));
if (pClusterID == NULL) {
goto HandleError;
}
*ppClusterInfo = (TSSD_ClusterInfo *) MIDL_user_allocate(sizeof(TSSD_ClusterInfo) *
*pNumberOfClusters);
pClusterInfo = *ppClusterInfo;
if (pClusterInfo == NULL) {
TSDISErrorOut(L"TSSDRpcQueryClusterInfo: Memory alloc failed!\n");
goto HandleError;
}
err = JetMove(sesid, clusdirtableid, JET_MoveFirst, 0);
i = 0;
while (err != JET_errNoCurrentRecord) {
CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_CLUSID_INTERNAL_INDEX], &pClusterID[i],
sizeof(pClusterID[i]), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_CLUSNAME_INTERNAL_INDEX], pClusterInfo[i].ClusterName,
sizeof(pClusterInfo[i].ClusterName), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_SINGLESESS_INTERNAL_INDEX], &(pClusterInfo[i].SingleSessionMode),
sizeof(pClusterInfo[i].SingleSessionMode), &cbActual, 0, NULL));
err = JetMove(sesid, clusdirtableid, JET_MoveNext, 0);
i++;
}
// Find the server numbers in this cluster
for (i=0; i<*pNumberOfClusters; i++) {
CALL(JetMove(sesid, servdirtableid, JET_MoveFirst, 0));
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ClusterIDIndex"));
CALL(JetMakeKey(sesid, servdirtableid, (const void *)&pClusterID[i], sizeof(pClusterID[i]),
JET_bitNewKey));
CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange));
CALL(JetIndexRecordCount(sesid, servdirtableid, &(pClusterInfo[i].NumberOfServers), TSSD_SERACH_MAX_RECORD));
TRC1((TB,"TSSDRpcQueryClusterInfo: Get ServerNum is %d", pClusterInfo[0].NumberOfServers));
}
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseTable(sesid, clusdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
rc = (DWORD)RPC_S_OK;
HandleError:
// Deallocate memory
if (pClusterID != NULL) {
LocalFree(pClusterID);
}
if ((sesid != JET_sesidNil) && (rc != 0)) {
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
return rc;
}
// Query the cluster info by the cluster name
DWORD TSSDRpcQueryClusterInfo(
/* [in] */ handle_t Binding,
/*[in] */ WCHAR __RPC_FAR *ClusterName,
/* [out] */ DWORD __RPC_FAR *pNumberOfClusters,
/* [out] */ TSSD_ClusterInfo __RPC_FAR __RPC_FAR **ppClusterInfo)
{
Binding;
TSSD_ClusterInfo *pClusterInfo;
DWORD rc = (DWORD) E_FAIL;
JET_SESID sesid = JET_sesidNil;
JET_TABLEID clusdirtableid;
JET_TABLEID servdirtableid;
JET_DBID dbid;
JET_ERR err;
long *pClusterID = NULL;
unsigned long cbActual;
DWORD i;
*pNumberOfClusters = 0;
pClusterInfo = NULL;
TRC1((TB,"Query for cluster Name: %S", ClusterName));
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
&clusdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetBeginTransaction(sesid));
// From the clustername find the clusterID
CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusNameIndex"));
CALL(JetMakeKey(sesid, clusdirtableid, ClusterName, (unsigned)
(wcslen(ClusterName) + 1) * sizeof(WCHAR), JET_bitNewKey));
err = JetSeek(sesid, clusdirtableid, JET_bitSeekEQ);
if (err != JET_errSuccess) {
TRC1((TB,"TSSDRpcQueryClusterInfo: Clustername %S does not exist", ClusterName));
goto HandleError;
}
*pNumberOfClusters = 1;
pClusterID = (long *)LocalAlloc(LMEM_FIXED, *pNumberOfClusters * sizeof(long));
if (pClusterID == NULL) {
TSDISErrorOut(L"TSSDRpcQueryClusterInfo: Memory alloc failed!\n");
goto HandleError;
}
*ppClusterInfo = (TSSD_ClusterInfo *) MIDL_user_allocate(sizeof(TSSD_ClusterInfo) *
*pNumberOfClusters);
pClusterInfo = *ppClusterInfo;
if (pClusterInfo == NULL) {
TSDISErrorOut(L"TSSDRpcQueryClusterInfo: Memory alloc failed!\n");
goto HandleError;
}
CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_CLUSID_INTERNAL_INDEX], &pClusterID[0],
sizeof(pClusterID[0]), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_CLUSNAME_INTERNAL_INDEX], pClusterInfo[0].ClusterName,
sizeof(pClusterInfo[0].ClusterName), &cbActual, 0, NULL));
TRC1((TB,"TSSDRpcQueryClusterInfo: Get cluster name %S", pClusterInfo[0].ClusterName));
CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_SINGLESESS_INTERNAL_INDEX], &(pClusterInfo[0].SingleSessionMode),
sizeof(pClusterInfo[0].SingleSessionMode), &cbActual, 0, NULL));
// Find the server numbers in this cluster
for (i=0; i<*pNumberOfClusters; i++) {
CALL(JetMove(sesid, servdirtableid, JET_MoveFirst, 0));
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ClusterIDIndex"));
CALL(JetMakeKey(sesid, servdirtableid, (const void *)&pClusterID[i], sizeof(pClusterID[i]),
JET_bitNewKey));
CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange));
CALL(JetIndexRecordCount(sesid, servdirtableid, &(pClusterInfo[i].NumberOfServers), TSSD_SERACH_MAX_RECORD));
TRC1((TB,"TSSDRpcQueryClusterInfo: Get ServerNum is %d", pClusterInfo[i].NumberOfServers));
}
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseTable(sesid, clusdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
rc = (DWORD)RPC_S_OK;
HandleError:
// Deallocate memory
if (pClusterID != NULL) {
LocalFree(pClusterID);
}
if ((sesid != JET_sesidNil) && (rc != 0)) {
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
return rc;
}
#pragma warning (pop)