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.

2065 lines
76 KiB

  1. /****************************************************************************/
  2. // jetrpcfn.cpp
  3. //
  4. // TS Directory Integrity Service Jet RPC server-side implementations.
  5. //
  6. // Copyright (C) 2000, Microsoft Corporation
  7. /****************************************************************************/
  8. #include "dis.h"
  9. #include "tssdshrd.h"
  10. #include "jetrpc.h"
  11. #include "jetsdis.h"
  12. #include "sdevent.h"
  13. #include <Lm.h>
  14. #pragma warning (push, 4)
  15. extern PSID g_pSid;
  16. extern DWORD g_dwClusterState;
  17. extern WCHAR *g_ClusterNetworkName;
  18. /****************************************************************************/
  19. // MIDL_user_allocate
  20. // MIDL_user_free
  21. //
  22. // RPC-required allocation functions.
  23. /****************************************************************************/
  24. void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t Size)
  25. {
  26. return LocalAlloc(LMEM_FIXED, Size);
  27. }
  28. void __RPC_USER MIDL_user_free(void __RPC_FAR *p)
  29. {
  30. LocalFree(p);
  31. }
  32. /****************************************************************************/
  33. // OutputAllTables (debug only)
  34. //
  35. // Output all tables to debug output.
  36. /****************************************************************************/
  37. #ifdef DBG
  38. void OutputAllTables()
  39. {
  40. JET_ERR err;
  41. JET_SESID sesid = JET_sesidNil;
  42. JET_DBID dbid;
  43. JET_TABLEID sessdirtableid;
  44. JET_TABLEID servdirtableid;
  45. JET_TABLEID clusdirtableid;
  46. JET_RETRIEVECOLUMN rcSessDir[NUM_SESSDIRCOLUMNS];
  47. WCHAR UserNameBuf[256];
  48. WCHAR DomainBuf[127];
  49. WCHAR ApplicationBuf[256];
  50. WCHAR ServerNameBuf[128];
  51. WCHAR ClusterNameBuf[128];
  52. WCHAR ServerDNSNameBuf[SDNAMELENGTH];
  53. unsigned count;
  54. long num_vals[NUM_SESSDIRCOLUMNS];
  55. char state;
  56. char SingleSessMode;
  57. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  58. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  59. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  60. &sessdirtableid));
  61. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  62. &servdirtableid));
  63. CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
  64. &clusdirtableid));
  65. CALL(JetBeginTransaction(sesid));
  66. TSDISErrorOut(L"SESSION DIRECTORY\n");
  67. err = JetMove(sesid, sessdirtableid, JET_MoveFirst, 0);
  68. if (JET_errNoCurrentRecord == err) {
  69. TSDISErrorOut(L" (empty database)\n");
  70. }
  71. while (JET_errNoCurrentRecord != err) {
  72. // Retrieve all the columns
  73. memset(&rcSessDir[0], 0, sizeof(JET_RETRIEVECOLUMN) *
  74. NUM_SESSDIRCOLUMNS);
  75. for (count = 0; count < NUM_SESSDIRCOLUMNS; count++) {
  76. rcSessDir[count].columnid = sesdircolumnid[count];
  77. rcSessDir[count].pvData = &num_vals[count];
  78. rcSessDir[count].cbData = sizeof(long);
  79. rcSessDir[count].itagSequence = 1;
  80. }
  81. // fix up pvData, cbData for non-int fields
  82. rcSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].pvData = UserNameBuf;
  83. rcSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].cbData = sizeof(UserNameBuf);
  84. rcSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].pvData = DomainBuf;
  85. rcSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].cbData = sizeof(DomainBuf);
  86. rcSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].pvData = ApplicationBuf;
  87. rcSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].cbData =
  88. sizeof(ApplicationBuf);
  89. rcSessDir[SESSDIR_STATE_INTERNAL_INDEX].pvData = &state;
  90. rcSessDir[SESSDIR_STATE_INTERNAL_INDEX].cbData = sizeof(state);
  91. CALL(JetRetrieveColumns(sesid, sessdirtableid, &rcSessDir[0],
  92. NUM_SESSDIRCOLUMNS));
  93. TSDISErrorOut(L"%8s, %s, %d, %d, %d\n",
  94. UserNameBuf,
  95. DomainBuf,
  96. num_vals[SESSDIR_SERVERID_INTERNAL_INDEX],
  97. num_vals[SESSDIR_SESSIONID_INTERNAL_INDEX],
  98. num_vals[SESSDIR_TSPROTOCOL_INTERNAL_INDEX]);
  99. TSDISErrorTimeOut(L" %s, ",
  100. num_vals[SESSDIR_CTLOW_INTERNAL_INDEX],
  101. num_vals[SESSDIR_CTHIGH_INTERNAL_INDEX]);
  102. TSDISErrorTimeOut(L"%s\n",
  103. num_vals[SESSDIR_DTLOW_INTERNAL_INDEX],
  104. num_vals[SESSDIR_DTHIGH_INTERNAL_INDEX]);
  105. TSDISErrorOut(L" %s, %d, %d, %d, %s\n",
  106. ApplicationBuf ? L"(no application)" : ApplicationBuf,
  107. num_vals[SESSDIR_RESWIDTH_INTERNAL_INDEX],
  108. num_vals[SESSDIR_RESHEIGHT_INTERNAL_INDEX],
  109. num_vals[SESSDIR_COLORDEPTH_INTERNAL_INDEX],
  110. state ? L"disconnected" : L"connected");
  111. err = JetMove(sesid, sessdirtableid, JET_MoveNext, 0);
  112. }
  113. // Output Server Directory (we are reusing the rcSessDir structure).
  114. TSDISErrorOut(L"SERVER DIRECTORY\n");
  115. err = JetMove(sesid, servdirtableid, JET_MoveFirst, 0);
  116. if (JET_errNoCurrentRecord == err) {
  117. TSDISErrorOut(L" (empty database)\n");
  118. }
  119. while (JET_errNoCurrentRecord != err) {
  120. // Retrieve all the columns.
  121. memset(&rcSessDir[0], 0, sizeof(JET_RETRIEVECOLUMN) *
  122. NUM_SERVDIRCOLUMNS);
  123. for (count = 0; count < NUM_SERVDIRCOLUMNS; count++) {
  124. rcSessDir[count].columnid = servdircolumnid[count];
  125. rcSessDir[count].pvData = &num_vals[count];
  126. rcSessDir[count].cbData = sizeof(long);
  127. rcSessDir[count].itagSequence = 1;
  128. }
  129. rcSessDir[SERVDIR_SERVADDR_INTERNAL_INDEX].pvData = ServerNameBuf;
  130. rcSessDir[SERVDIR_SERVADDR_INTERNAL_INDEX].cbData =
  131. sizeof(ServerNameBuf);
  132. rcSessDir[SERVDIR_SERVDNSNAME_INTERNAL_INDEX].pvData = ServerDNSNameBuf;
  133. rcSessDir[SERVDIR_SERVDNSNAME_INTERNAL_INDEX].cbData =
  134. sizeof(ServerDNSNameBuf);
  135. rcSessDir[SERVDIR_SINGLESESS_INTERNAL_INDEX].pvData = &SingleSessMode;
  136. rcSessDir[SERVDIR_SINGLESESS_INTERNAL_INDEX].cbData = sizeof(SingleSessMode);
  137. CALL(JetRetrieveColumns(sesid, servdirtableid, &rcSessDir[0],
  138. NUM_SERVDIRCOLUMNS));
  139. TSDISErrorOut(L"%d, %s, %d, %d, %d, %d, %s\n", num_vals[
  140. SERVDIR_SERVID_INTERNAL_INDEX], ServerNameBuf, num_vals[
  141. SERVDIR_CLUSID_INTERNAL_INDEX], num_vals[
  142. SERVDIR_AITLOW_INTERNAL_INDEX], num_vals[
  143. SERVDIR_AITHIGH_INTERNAL_INDEX], num_vals[
  144. SERVDIR_NUMFAILPINGS_INTERNAL_INDEX], SingleSessMode ?
  145. L"single session mode" : L"multi-session mode");
  146. err = JetMove(sesid, servdirtableid, JET_MoveNext, 0);
  147. }
  148. // Output Cluster Directory
  149. TSDISErrorOut(L"CLUSTER DIRECTORY\n");
  150. err = JetMove(sesid, clusdirtableid, JET_MoveFirst, 0);
  151. if (JET_errNoCurrentRecord == err) {
  152. TSDISErrorOut(L" (empty database)\n");
  153. }
  154. while (JET_errNoCurrentRecord != err) {
  155. memset(&rcSessDir[0], 0, sizeof(JET_RETRIEVECOLUMN) *
  156. NUM_CLUSDIRCOLUMNS);
  157. for (count = 0; count < NUM_CLUSDIRCOLUMNS; count++) {
  158. rcSessDir[count].columnid = clusdircolumnid[count];
  159. rcSessDir[count].pvData = &num_vals[count];
  160. rcSessDir[count].cbData = sizeof(long);
  161. rcSessDir[count].itagSequence = 1;
  162. }
  163. rcSessDir[CLUSDIR_CLUSNAME_INTERNAL_INDEX].pvData = ClusterNameBuf;
  164. rcSessDir[CLUSDIR_CLUSNAME_INTERNAL_INDEX].cbData =
  165. sizeof(ClusterNameBuf);
  166. rcSessDir[CLUSDIR_SINGLESESS_INTERNAL_INDEX].pvData = &SingleSessMode;
  167. rcSessDir[CLUSDIR_SINGLESESS_INTERNAL_INDEX].cbData =
  168. sizeof(SingleSessMode);
  169. CALL(JetRetrieveColumns(sesid, clusdirtableid, &rcSessDir[0],
  170. NUM_CLUSDIRCOLUMNS));
  171. TSDISErrorOut(L"%d, %s, %s\n", num_vals[CLUSDIR_CLUSID_INTERNAL_INDEX],
  172. ClusterNameBuf, SingleSessMode ? L"single session mode" :
  173. L"multi-session mode");
  174. err = JetMove(sesid, clusdirtableid, JET_MoveNext, 0);
  175. }
  176. TSDISErrorOut(L"\n");
  177. CALL(JetCommitTransaction(sesid, 0));
  178. CALL(JetCloseTable(sesid, servdirtableid));
  179. CALL(JetCloseTable(sesid, sessdirtableid));
  180. CALL(JetCloseTable(sesid, clusdirtableid));
  181. CALL(JetCloseDatabase(sesid, dbid, 0));
  182. CALL(JetEndSession(sesid, 0));
  183. return;
  184. HandleError:
  185. if (sesid != JET_sesidNil) {
  186. // Can't really recover. Just bail out.
  187. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  188. // Force the session closed
  189. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  190. }
  191. }
  192. #endif //DBG
  193. typedef DWORD CLIENTINFO;
  194. long
  195. DeleteExistingServerSession(
  196. JET_SESID sesid,
  197. JET_TABLEID sessdirtableid,
  198. CLIENTINFO *pCI,
  199. DWORD SessionID
  200. )
  201. /*++
  202. --*/
  203. {
  204. JET_ERR err = JET_errSuccess;
  205. DWORD dwNumRecordDeleted = 0;
  206. TSDISErrorOut(L"In DeleteExistingServerSession, ServID=%d, "
  207. L"SessID=%d\n", *pCI, SessionID);
  208. ASSERT( (sesid != JET_sesidNil), (TB, "Invalid JETBLUE Session...") );
  209. // Delete all sessions in session directory that have this Server ID/Session ID
  210. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "primaryIndex"));
  211. CALL(JetMakeKey(sesid, sessdirtableid, pCI, sizeof(*pCI), JET_bitNewKey));
  212. CALL(JetMakeKey(sesid, sessdirtableid, &SessionID, sizeof(SessionID), 0));
  213. err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange);
  214. while ( JET_errSuccess == err ) {
  215. // TODO - check build, retrieve server id and session Id, assert if not equal to what
  216. // we looking for
  217. CALL(JetDelete(sesid, sessdirtableid));
  218. dwNumRecordDeleted++;
  219. // Move to the next matching record.
  220. err = JetMove(sesid, sessdirtableid, JET_MoveNext, 0);
  221. }
  222. ASSERT( (dwNumRecordDeleted < 2), (TB, "Delete %d record...", dwNumRecordDeleted) );
  223. TSDISErrorOut(L"Deleted %d for ServID=%d, "
  224. L"SessID=%d\n", dwNumRecordDeleted, *pCI, SessionID);
  225. return dwNumRecordDeleted;
  226. HandleError:
  227. // the only way to come here is error in one of Jet call wrap around CALL.
  228. ASSERT( (err == JET_errSuccess), (TB, "Error in DeleteExistingServerSession %d", err) );
  229. return -1;
  230. }
  231. /****************************************************************************/
  232. // SDRPCAccessCheck
  233. //
  234. // Check if this RPC caller havs access right or not
  235. /****************************************************************************/
  236. RPC_STATUS RPC_ENTRY SDRPCAccessCheck(RPC_IF_HANDLE idIF, void *Binding)
  237. {
  238. RPC_STATUS rpcStatus, rc;
  239. HANDLE hClientToken = NULL;
  240. DWORD Error;
  241. BOOL AccessStatus = FALSE;
  242. RPC_AUTHZ_HANDLE hPrivs;
  243. DWORD dwAuthn;
  244. RPC_BINDING_HANDLE ServerBinding = 0;
  245. WCHAR *StringBinding = NULL;
  246. WCHAR *ServerAddress = NULL;
  247. idIF;
  248. if (RpcBindingServerFromClient(Binding, &ServerBinding) != RPC_S_OK) {
  249. TSDISErrorOut(L"In SDRPCAccessCheck: BindingServerFromClient failed!\n");
  250. goto HandleError;
  251. }
  252. if (RpcBindingToStringBinding(ServerBinding, &StringBinding) != RPC_S_OK) {
  253. TSDISErrorOut(L"In SDRPCAccessCheck: BindingToStringBinding failed!\n");
  254. goto HandleError;
  255. }
  256. if (RpcStringBindingParse(StringBinding, NULL, NULL, &ServerAddress, NULL,
  257. NULL) != RPC_S_OK) {
  258. TSDISErrorOut(L"In SDRPCAccessCheck: StringBindingParse failed!\n");
  259. goto HandleError;
  260. }
  261. // Check if the client uses the protocol sequence we expect
  262. if (!CheckRPCClientProtoSeq(Binding, L"ncacn_ip_tcp")) {
  263. TSDISErrorOut(L"In SDRPCAccessCheck: Client doesn't use the tcpip protocol sequence\n");
  264. goto HandleError;
  265. }
  266. // Check what security level the client uses
  267. rpcStatus = RpcBindingInqAuthClient(Binding,
  268. &hPrivs,
  269. NULL,
  270. &dwAuthn,
  271. NULL,
  272. NULL);
  273. if (rpcStatus != RPC_S_OK) {
  274. TSDISErrorOut(L"In SDRPCAccessCheck: RpcBindingIngAuthClient fails with %u\n", rpcStatus);
  275. goto HandleError;
  276. }
  277. // We request at least privacy-level authentication
  278. if (dwAuthn < RPC_C_AUTHN_LEVEL_PKT_PRIVACY) {
  279. TSDISErrorOut(L"In SDRPCAccessCheck: Attemp by client to use weak authentication\n");
  280. goto HandleError;
  281. }
  282. // Check the access right of this rpc call
  283. rpcStatus = RpcImpersonateClient(Binding);
  284. if (RPC_S_OK != rpcStatus) {
  285. TSDISErrorOut(L"In SDRPCAccessCheck: RpcImpersonateClient fail with %u\n", rpcStatus);
  286. goto HandleError;
  287. }
  288. // get our impersonated token
  289. if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hClientToken)) {
  290. Error = GetLastError();
  291. TSDISErrorOut(L"In SDRPCAccessCheck: OpenThreadToken Error %u\n", Error);
  292. RpcRevertToSelf();
  293. goto HandleError;
  294. }
  295. RpcRevertToSelf();
  296. if (!CheckTokenMembership(hClientToken,
  297. g_pSid,
  298. &AccessStatus)) {
  299. AccessStatus = FALSE;
  300. Error = GetLastError();
  301. TSDISErrorOut(L"In SDRPCAccessCheck: CheckTokenMembership fails with %u\n", Error);
  302. }
  303. HandleError:
  304. if (AccessStatus) {
  305. rc = RPC_S_OK;
  306. }
  307. else {
  308. if (ServerAddress) {
  309. TSDISErrorOut(L"In SDRPCAccessCheck: Unauthorized RPC call from server %s\n", ServerAddress);
  310. PostSessDirErrorMsgEvent(EVENT_FAIL_RPC_DENY_ACCESS, ServerAddress, EVENTLOG_ERROR_TYPE);
  311. }
  312. rc = ERROR_ACCESS_DENIED;
  313. }
  314. if (hClientToken != NULL) {
  315. CloseHandle(hClientToken);
  316. }
  317. if (ServerBinding != NULL)
  318. RpcBindingFree(&ServerBinding);
  319. if (StringBinding != NULL)
  320. RpcStringFree(&StringBinding);
  321. if (ServerAddress != NULL)
  322. RpcStringFree(&ServerAddress);
  323. return rc;
  324. }
  325. /****************************************************************************/
  326. // TSSDRpcServerOnline
  327. //
  328. // Called for server-active indications on each cluster TS machine.
  329. /****************************************************************************/
  330. DWORD TSSDRpcServerOnline(
  331. handle_t Binding,
  332. WCHAR __RPC_FAR *ClusterName,
  333. /* out */ HCLIENTINFO *hCI,
  334. DWORD SrvOnlineFlags,
  335. /* in, out */ WCHAR *ComputerName,
  336. /* in */ WCHAR *ServerIPAddr)
  337. {
  338. JET_ERR err;
  339. JET_SESID sesid = JET_sesidNil;
  340. JET_DBID dbid;
  341. JET_TABLEID clusdirtableid;
  342. JET_TABLEID servdirtableid;
  343. JET_SETCOLUMN scServDir[NUM_SERVDIRCOLUMNS];
  344. WCHAR *StringBinding = NULL;
  345. WCHAR *ServerAddress = NULL;
  346. RPC_BINDING_HANDLE ServerBinding = 0;
  347. unsigned long cbActual;
  348. long ClusterID;
  349. long ServerID = 0;
  350. long zero = 0;
  351. // The single session mode of this server.
  352. char SingleSession = (char) SrvOnlineFlags & SINGLE_SESSION_FLAG;
  353. char ClusSingleSessionMode;
  354. unsigned count;
  355. DWORD rc = (DWORD) E_FAIL;
  356. DWORD cchBuff;
  357. WCHAR ServerDNSName[SDNAMELENGTH];
  358. // "unreferenced" parameter (referenced by RPC)
  359. Binding;
  360. ServerIPAddr;
  361. TSDISErrorOut(L"In ServOnline, ClusterName=%s, SrvOnlineFlags=%u\n",
  362. ClusterName, SrvOnlineFlags);
  363. // Make a copy of TS server DNS server name
  364. wcsncpy(ServerDNSName, ComputerName, SDNAMELENGTH);
  365. TSDISErrorOut(L"In ServOnline, the Server Name is %s\n", ServerDNSName);
  366. // Determine client address.
  367. if (RpcBindingServerFromClient(Binding, &ServerBinding) != RPC_S_OK) {
  368. TSDISErrorOut(L"ServOn: BindingServerFromClient failed!\n");
  369. goto HandleError;
  370. }
  371. if (RpcBindingToStringBinding(ServerBinding, &StringBinding) != RPC_S_OK) {
  372. TSDISErrorOut(L"ServOn: BindingToStringBinding failed!\n");
  373. goto HandleError;
  374. }
  375. if (RpcStringBindingParse(StringBinding, NULL, NULL, &ServerAddress, NULL,
  376. NULL) != RPC_S_OK) {
  377. TSDISErrorOut(L"ServOn: StringBindingParse failed!\n");
  378. goto HandleError;
  379. }
  380. //TSDISErrorOut(L"In ServOnline, ServerAddress is %s\n",
  381. // ServerAddress);
  382. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  383. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  384. CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
  385. &clusdirtableid));
  386. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  387. &servdirtableid));
  388. // This server comes with NO_REPOPULATE_SESSION flag
  389. // We will reuse its info in the database
  390. if (SrvOnlineFlags & NO_REPOPULATE_SESSION) {
  391. CALL(JetBeginTransaction(sesid));
  392. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServDNSNameIndex"));
  393. CALL(JetMakeKey(sesid, servdirtableid, ServerDNSName, (unsigned)
  394. (wcslen(ServerDNSName) + 1) * sizeof(WCHAR), JET_bitNewKey));
  395. err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ);
  396. if (JET_errSuccess == err) {
  397. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  398. SERVDIR_SERVID_INTERNAL_INDEX], &ServerID, sizeof(ServerID),
  399. &cbActual, 0, NULL));
  400. *hCI = ULongToPtr(ServerID);
  401. TSDISErrorOut(L"In ServOnline, ServerID is %d\n", *hCI);
  402. } else {
  403. // If we can't find this server, fail ServOnline call and server will rejoin SD
  404. TSDISErrorOut(L"ServOn: This server with no-populate flag can't be found\n");
  405. goto HandleError;
  406. }
  407. CALL(JetCommitTransaction(sesid, 0));
  408. goto NormalExit;
  409. }
  410. // First, delete all entries for this server from the session/server
  411. //directories
  412. CALL(JetBeginTransaction(sesid));
  413. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServDNSNameIndex"));
  414. CALL(JetMakeKey(sesid, servdirtableid, ServerDNSName, (unsigned)
  415. (wcslen(ServerDNSName) + 1) * sizeof(WCHAR), JET_bitNewKey));
  416. err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ);
  417. if (JET_errSuccess == err) {
  418. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  419. SERVDIR_SERVID_INTERNAL_INDEX], &ServerID, sizeof(ServerID),
  420. &cbActual, 0, NULL));
  421. if (TSSDPurgeServer(ServerID) != 0)
  422. TSDISErrorOut(L"ServOn: PurgeServer %d failed.\n", ServerID);
  423. } else if (JET_errRecordNotFound != err) {
  424. CALL(err);
  425. }
  426. CALL(JetCommitTransaction(sesid, 0));
  427. // We have to do the add in a loop, because we have to:
  428. // 1) Check if the record is there.
  429. // 2) If it's not, add it. (The next time through the loop, therefore,
  430. // we'll go step 1->3, and we're done.)
  431. // 3) If it is, retrieve the value of clusterID and break out.
  432. //
  433. // There is an additional complication in that someone else may be in the
  434. // thread simultaneously, doing the same thing. Therefore, someone might
  435. // be in step 2 and try to add a new cluster, but fail because someone
  436. // else added it. So they have to keep trying, because though the other
  437. // thread has added it, it may not have committed the change. To try to
  438. // keep that to a minimum, we sleep a short time before trying again.
  439. for ( ; ; ) {
  440. // Now do the actual add.
  441. CALL(JetBeginTransaction(sesid));
  442. // Search for the cluster in the cluster directory.
  443. CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusNameIndex"));
  444. CALL(JetMakeKey(sesid, clusdirtableid, ClusterName, (unsigned)
  445. (wcslen(ClusterName) + 1) * sizeof(WCHAR), JET_bitNewKey));
  446. err = JetSeek(sesid, clusdirtableid, JET_bitSeekEQ);
  447. // If the cluster does not exist, create it.
  448. if (JET_errRecordNotFound == err) {
  449. CALL(JetPrepareUpdate(sesid, clusdirtableid, JET_prepInsert));
  450. // ClusterName
  451. CALL(JetSetColumn(sesid, clusdirtableid, clusdircolumnid[
  452. CLUSDIR_CLUSNAME_INTERNAL_INDEX], ClusterName,
  453. (unsigned) (wcslen(ClusterName) + 1) * sizeof(WCHAR), 0,
  454. NULL));
  455. // SingleSessionMode
  456. // Since this is the only server in the cluster, the single session
  457. // mode is simply the mode of this server.
  458. CALL(JetSetColumn(sesid, clusdirtableid, clusdircolumnid[
  459. CLUSDIR_SINGLESESS_INTERNAL_INDEX], &SingleSession,
  460. sizeof(SingleSession), 0, NULL));
  461. err = JetUpdate(sesid, clusdirtableid, NULL, 0, &cbActual);
  462. // If it's a duplicate key, someone else made the key so we should
  463. // be ok. Yield the processor and try the query again, next time
  464. // through the loop.
  465. if (JET_errKeyDuplicate == err) {
  466. CALL(JetCommitTransaction(sesid, 0));
  467. Sleep(100);
  468. }
  469. else {
  470. CALL(err);
  471. // Now we've succeeded. Just continue through the loop.
  472. // The next time through, we will retrieve the autoincrement
  473. // column we just added and break out.
  474. CALL(JetCommitTransaction(sesid, 0));
  475. }
  476. }
  477. else {
  478. CALL(err);
  479. // If the above check makes it here, we have found the row.
  480. // Now retrieve the clusid, commit, and break out of the loop.
  481. CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
  482. CLUSDIR_CLUSID_INTERNAL_INDEX], &ClusterID,
  483. sizeof(ClusterID), &cbActual, 0, NULL));
  484. CALL(JetCommitTransaction(sesid, 0));
  485. break;
  486. }
  487. }
  488. CALL(JetBeginTransaction(sesid));
  489. // Insert the servername, clusterid, 0, 0 into the server directory table
  490. err = JetMove(sesid, servdirtableid, JET_MoveLast, 0);
  491. CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepInsert));
  492. memset(&scServDir[0], 0, sizeof(JET_SETCOLUMN) * NUM_SERVDIRCOLUMNS);
  493. for (count = 0; count < NUM_SERVDIRCOLUMNS; count++) {
  494. scServDir[count].columnid = servdircolumnid[count];
  495. scServDir[count].cbData = 4; // most of them, set the rest individually
  496. scServDir[count].itagSequence = 1;
  497. }
  498. scServDir[SERVDIR_SERVADDR_INTERNAL_INDEX].pvData = ServerAddress;
  499. scServDir[SERVDIR_SERVADDR_INTERNAL_INDEX].cbData =
  500. (unsigned) (wcslen(ServerAddress) + 1) * sizeof(WCHAR);
  501. scServDir[SERVDIR_CLUSID_INTERNAL_INDEX].pvData = &ClusterID;
  502. scServDir[SERVDIR_AITLOW_INTERNAL_INDEX].pvData = &zero;
  503. scServDir[SERVDIR_AITHIGH_INTERNAL_INDEX].pvData = &zero;
  504. scServDir[SERVDIR_NUMFAILPINGS_INTERNAL_INDEX].pvData = &zero;
  505. scServDir[SERVDIR_SINGLESESS_INTERNAL_INDEX].pvData = &SingleSession;
  506. scServDir[SERVDIR_SINGLESESS_INTERNAL_INDEX].cbData = sizeof(SingleSession);
  507. scServDir[SERVDIR_SERVDNSNAME_INTERNAL_INDEX].pvData = ServerDNSName;
  508. scServDir[SERVDIR_SERVDNSNAME_INTERNAL_INDEX].cbData =
  509. (unsigned) (wcslen(ServerDNSName) + 1) * sizeof(WCHAR);
  510. // Don't set the first column (index 0)--it is autoincrement.
  511. CALL(JetSetColumns(sesid, servdirtableid, &scServDir[
  512. SERVDIR_SERVADDR_INTERNAL_INDEX], NUM_SERVDIRCOLUMNS - 1));
  513. CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
  514. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServNameIndex"));
  515. CALL(JetMakeKey(sesid, servdirtableid, ServerAddress, (unsigned)
  516. (wcslen(ServerAddress) + 1) * sizeof(WCHAR), JET_bitNewKey));
  517. CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
  518. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  519. SERVDIR_SERVID_INTERNAL_INDEX], &ServerID, sizeof(ServerID),
  520. &cbActual, 0, NULL));
  521. *hCI = ULongToPtr(ServerID);
  522. TSDISErrorOut(L"In ServOnline, ServerID is %d\n", *hCI);
  523. // Now that the server is all set up, we have to set the cluster to the
  524. // correct mode. If any server in the cluster is in multisession mode, then
  525. // we stick with multisession. If they are all single session, though, we
  526. // turn on single session in this cluster.
  527. // Check the cluster to see if its single-session mode.
  528. CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusIDIndex"));
  529. CALL(JetMakeKey(sesid, clusdirtableid, (const void *)&ClusterID,
  530. sizeof(ClusterID), JET_bitNewKey));
  531. CALL(JetSeek(sesid, clusdirtableid, JET_bitSeekEQ));
  532. CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
  533. CLUSDIR_SINGLESESS_INTERNAL_INDEX], &ClusSingleSessionMode, sizeof(
  534. ClusSingleSessionMode), &cbActual, 0, NULL));
  535. // If the new server is multi-session mode and cluster is single-session, change the mode.
  536. if ((SingleSession == 0) && (ClusSingleSessionMode != SingleSession)) {
  537. err = JetPrepareUpdate(sesid, clusdirtableid, JET_prepReplace);
  538. if (JET_errWriteConflict == err) {
  539. // Another thread is updating this setting, so no need to update
  540. }
  541. else {
  542. CALL(err);
  543. CALL(JetSetColumn(sesid, clusdirtableid, clusdircolumnid[
  544. CLUSDIR_SINGLESESS_INTERNAL_INDEX], &SingleSession,
  545. sizeof(SingleSession), 0, NULL));
  546. CALL(JetUpdate(sesid, clusdirtableid, NULL, 0, &cbActual));
  547. }
  548. }
  549. CALL(JetCommitTransaction(sesid, 0));
  550. NormalExit:
  551. CALL(JetCloseTable(sesid, servdirtableid));
  552. CALL(JetCloseTable(sesid, clusdirtableid));
  553. CALL(JetCloseDatabase(sesid, dbid, 0));
  554. CALL(JetEndSession(sesid, 0));
  555. // Get the local computer name
  556. cchBuff = SDNAMELENGTH - 2;
  557. if (g_dwClusterState == ClusterStateRunning) {
  558. // return ClusterNetworkName as the computer name if it's
  559. // running on fail-over cluster
  560. wcsncpy(ComputerName, g_ClusterNetworkName, cchBuff);
  561. }
  562. else {
  563. if (!GetComputerNameEx(ComputerNamePhysicalNetBIOS, ComputerName, &cchBuff)) {
  564. TSDISErrorOut(L"GetComputerNameEx fails with 0x%x\n", GetLastError());
  565. goto HandleError;
  566. }
  567. }
  568. wcscat(ComputerName, L"$");
  569. if (ServerBinding != NULL)
  570. RpcBindingFree(&ServerBinding);
  571. if (StringBinding != NULL)
  572. RpcStringFree(&StringBinding);
  573. if (ServerAddress != NULL)
  574. RpcStringFree(&ServerAddress);
  575. return 0;
  576. HandleError:
  577. if (sesid != JET_sesidNil) {
  578. // Can't really recover. Just bail out.
  579. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  580. // Force the session closed
  581. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  582. }
  583. TSDISErrorOut(L"ERROR : ServOnline %s failed with possible error code %d, start TSSDPurgeServer\n", ComputerName, err);
  584. if (ServerBinding != NULL)
  585. RpcBindingFree(&ServerBinding);
  586. if (StringBinding != NULL)
  587. RpcStringFree(&StringBinding);
  588. if (ServerAddress != NULL)
  589. RpcStringFree(&ServerAddress);
  590. // Just in case we got to commit.
  591. if (ServerID != 0)
  592. TSSDPurgeServer(ServerID);
  593. // Close the context handle.
  594. *hCI = NULL;
  595. return rc;
  596. }
  597. /****************************************************************************/
  598. // TSSDRpcServerOffline
  599. //
  600. // Called for server-shutdown indications on each cluster TS machine.
  601. /****************************************************************************/
  602. DWORD TSSDRpcServerOffline(
  603. handle_t Binding,
  604. HCLIENTINFO *hCI)
  605. {
  606. DWORD retval = 0;
  607. // "unreferenced" parameter (referenced by RPC)
  608. Binding;
  609. TSDISErrorOut(L"WARNING: In ServOff, hCI = 0x%x\n", *hCI);
  610. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  611. if (pCI != NULL)
  612. retval = TSSDPurgeServer(*pCI);
  613. *hCI = NULL;
  614. return retval;
  615. }
  616. /****************************************************************************/
  617. // TSSDPurgeServer
  618. //
  619. // Delete a server and all its sessions from the session directory.
  620. /****************************************************************************/
  621. DWORD TSSDPurgeServer(
  622. DWORD ServerID)
  623. {
  624. JET_SESID sesid = JET_sesidNil;
  625. JET_TABLEID sessdirtableid;
  626. JET_TABLEID servdirtableid;
  627. JET_TABLEID clusdirtableid;
  628. JET_DBID dbid;
  629. JET_ERR err;
  630. long ClusterID;
  631. unsigned long cbActual;
  632. char MultiSession = 0;
  633. char SingleSessionMode;
  634. WCHAR Msg[SDNAMELENGTH * 2 + 3], ServerIP[SDNAMELENGTH];
  635. DWORD numSessionDeleted = 0; // number of session deleted for this server
  636. BOOL bLoadServerIPSucceeeded = FALSE; // successful in loading serverip from table
  637. // initialize string for event log
  638. ZeroMemory( Msg, sizeof(Msg) );
  639. ZeroMemory( ServerIP, sizeof(ServerIP) );
  640. TSDISErrorOut(L"WARNING: In PurgeServer, ServerID=%d\n", ServerID);
  641. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  642. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  643. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  644. &sessdirtableid));
  645. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  646. &servdirtableid));
  647. CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
  648. &clusdirtableid));
  649. CALL(JetBeginTransaction(sesid));
  650. // Delete all sessions in session directory that have this serverid
  651. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "ServerIndex"));
  652. CALL(JetMakeKey(sesid, sessdirtableid, &ServerID, sizeof(ServerID),
  653. JET_bitNewKey));
  654. err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ);
  655. while (0 == err) {
  656. CALL(JetDelete(sesid, sessdirtableid));
  657. numSessionDeleted++;
  658. CALL(JetMakeKey(sesid, sessdirtableid, &ServerID, sizeof(ServerID),
  659. JET_bitNewKey));
  660. err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ);
  661. }
  662. // Should be err -1601 -- JET_errRecordNotFound
  663. // Delete the server in the server directory with this serverid
  664. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
  665. CALL(JetMakeKey(sesid, servdirtableid, &ServerID, sizeof(ServerID),
  666. JET_bitNewKey));
  667. err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ);
  668. if (JET_errSuccess == err) {
  669. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  670. SERVDIR_CLUSID_INTERNAL_INDEX], &ClusterID,
  671. sizeof(ClusterID), &cbActual, 0, NULL));
  672. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  673. SERVDIR_SINGLESESS_INTERNAL_INDEX], &SingleSessionMode,
  674. sizeof(SingleSessionMode), &cbActual, 0, NULL));
  675. // Get the server DNS name and IP
  676. cbActual = SDNAMELENGTH * sizeof(WCHAR);
  677. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  678. SERVDIR_SERVDNSNAME_INTERNAL_INDEX], Msg,
  679. cbActual, &cbActual, 0, NULL));
  680. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  681. SERVDIR_SERVADDR_INTERNAL_INDEX], ServerIP,
  682. sizeof(ServerIP), &cbActual, 0, NULL));
  683. bLoadServerIPSucceeeded = TRUE;
  684. CALL(JetDelete(sesid, servdirtableid));
  685. // If the server is the only one in cluster, delete this cluster in cluster directory
  686. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ClusterIDIndex"));
  687. CALL(JetMakeKey(sesid, servdirtableid, &ClusterID, sizeof(ClusterID),
  688. JET_bitNewKey));
  689. err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ);
  690. if (JET_errRecordNotFound == err) {
  691. // There's no other server in this cluster, delete this cluster
  692. CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusIDIndex"));
  693. CALL(JetMakeKey(sesid, clusdirtableid, &ClusterID, sizeof(ClusterID), JET_bitNewKey));
  694. err = JetSeek(sesid, clusdirtableid, JET_bitSeekEQ);
  695. if (JET_errSuccess == err)
  696. {
  697. CALL(JetDelete(sesid, clusdirtableid));
  698. }
  699. }
  700. else {
  701. CALL(err);
  702. // Update the SingleSessionMode of the cluster
  703. // If server removed is SingleSession, the cluster single session mode won't be affected
  704. // otherwise, seach the sever table for server in the cluster with multi-session mode
  705. // if not found, change the cluster single-session mode to single-session, otherwise do nothing
  706. if (SingleSessionMode == 0) {
  707. CALL(JetSetCurrentIndex(sesid, servdirtableid, "SingleSessionIndex"));
  708. CALL(JetMakeKey(sesid, servdirtableid, &ClusterID, sizeof(ClusterID),
  709. JET_bitNewKey));
  710. CALL(JetMakeKey(sesid, servdirtableid, &MultiSession, sizeof(MultiSession),
  711. 0));
  712. err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ);
  713. if (JET_errRecordNotFound == err) {
  714. // Set the cluster single-session mode to True
  715. SingleSessionMode = (char)1;
  716. CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusIDIndex"));
  717. CALL(JetMakeKey(sesid, clusdirtableid, &ClusterID, sizeof(ClusterID), JET_bitNewKey));
  718. CALL(JetSeek(sesid, clusdirtableid, JET_bitSeekEQ));
  719. CALL(JetPrepareUpdate(sesid, clusdirtableid, JET_prepReplace));
  720. CALL(JetSetColumn(sesid, clusdirtableid, clusdircolumnid[
  721. CLUSDIR_SINGLESESS_INTERNAL_INDEX], &SingleSessionMode, sizeof(SingleSessionMode), 0, NULL));
  722. CALL(JetUpdate(sesid, clusdirtableid, NULL, 0, &cbActual));
  723. }
  724. }
  725. }
  726. }
  727. CALL(JetCommitTransaction(sesid, 0));
  728. CALL(JetCloseTable(sesid, servdirtableid));
  729. CALL(JetCloseTable(sesid, sessdirtableid));
  730. CALL(JetCloseDatabase(sesid, dbid, 0));
  731. CALL(JetEndSession(sesid, 0));
  732. // we don't want to log event if we can't load serverIP from table.
  733. if( bLoadServerIPSucceeeded )
  734. {
  735. // Construct log msg to record TS leaving SD
  736. wcscat(Msg, L"(");
  737. wcsncat(Msg, ServerIP, SDNAMELENGTH);
  738. wcscat(Msg, L")");
  739. PostSessDirErrorMsgEvent(EVENT_SUCCESS_LEAVE_SESSIONDIRECTORY, Msg, EVENTLOG_SUCCESS);
  740. }
  741. else
  742. {
  743. TSDISErrorOut(L"WARNING: In PurgeServer() deleted %d "
  744. L"sessions for ServerID=%d but failed to load IP\n", numSessionDeleted, ServerID);
  745. }
  746. return 0;
  747. HandleError:
  748. if (sesid != JET_sesidNil) {
  749. // Can't really recover. Just bail out.
  750. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  751. // Force the session closed
  752. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  753. }
  754. return (DWORD) E_FAIL;
  755. }
  756. /****************************************************************************/
  757. // TSSDRpcGetUserDisconnectedSessions
  758. //
  759. // Queries disconnected sessions from the session database.
  760. /****************************************************************************/
  761. DWORD TSSDRpcGetUserDisconnectedSessions(
  762. handle_t Binding,
  763. HCLIENTINFO *hCI,
  764. WCHAR __RPC_FAR *UserName,
  765. WCHAR __RPC_FAR *Domain,
  766. /* out */ DWORD __RPC_FAR *pNumSessions,
  767. /* out */ TSSD_DiscSessInfo __RPC_FAR __RPC_FAR **padsi)
  768. {
  769. JET_ERR err;
  770. JET_SESID sesid = JET_sesidNil;
  771. JET_DBID dbid;
  772. JET_TABLEID sessdirtableid;
  773. JET_TABLEID servdirtableid;
  774. JET_TABLEID clusdirtableid;
  775. *pNumSessions = 0;
  776. unsigned i = 0;
  777. unsigned j = 0;
  778. unsigned long cbActual;
  779. DWORD tempClusterID;
  780. DWORD CallingServersClusID;
  781. long ServerID;
  782. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  783. TSSD_DiscSessInfo *adsi = NULL;
  784. char one = 1;
  785. char bSingleSession = 0;
  786. // "unreferenced" parameter (referenced by RPC)
  787. Binding;
  788. TSDISErrorOut(L"In GetUserDiscSess: ServID = %d, User: %s, "
  789. L"Domain: %s\n", *pCI, UserName, Domain);
  790. *padsi = (TSSD_DiscSessInfo *) MIDL_user_allocate(sizeof(TSSD_DiscSessInfo) *
  791. TSSD_MaxDisconnectedSessions);
  792. adsi = *padsi;
  793. if (adsi == NULL) {
  794. TSDISErrorOut(L"GetUserDisc: Memory alloc failed!\n");
  795. goto HandleError;
  796. }
  797. // Set the pointers to 0 to be safe, and so that we can free uninitialized
  798. // ones later without AVing.
  799. for (j = 0; j < TSSD_MaxDisconnectedSessions; j++) {
  800. adsi[j].ServerAddress = NULL;
  801. adsi[j].AppType = NULL;
  802. }
  803. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  804. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  805. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  806. &sessdirtableid));
  807. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  808. &servdirtableid));
  809. CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
  810. &clusdirtableid));
  811. CALL(JetBeginTransaction(sesid));
  812. // Verify that the ServerID passed in was OK.
  813. if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
  814. TSDISErrorOut(L"Invalid ServerID was passed in\n");
  815. goto HandleError;
  816. }
  817. // First, get the cluster ID for the server making the query.
  818. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
  819. CALL(JetMakeKey(sesid, servdirtableid, (const void *)pCI, sizeof(DWORD),
  820. JET_bitNewKey));
  821. CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
  822. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  823. SERVDIR_CLUSID_INTERNAL_INDEX], &CallingServersClusID, sizeof(
  824. CallingServersClusID), &cbActual, 0, NULL));
  825. // Now that we have the cluster id, check to see whether this cluster
  826. // is in single session mode.
  827. CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusIDIndex"));
  828. CALL(JetMakeKey(sesid, clusdirtableid, (const void *)&CallingServersClusID,
  829. sizeof(CallingServersClusID), JET_bitNewKey));
  830. CALL(JetSeek(sesid, clusdirtableid, JET_bitSeekEQ));
  831. CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
  832. CLUSDIR_SINGLESESS_INTERNAL_INDEX], &bSingleSession, sizeof(
  833. bSingleSession), &cbActual, 0, NULL));
  834. // Now, get all the disconnected or all sessions for this cluster, depending
  835. // on the single session mode retrieved above.
  836. if (bSingleSession == FALSE) {
  837. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "DiscSessionIndex"));
  838. CALL(JetMakeKey(sesid, sessdirtableid, UserName, (unsigned)
  839. (wcslen(UserName) + 1) * sizeof(WCHAR), JET_bitNewKey));
  840. CALL(JetMakeKey(sesid, sessdirtableid, Domain, (unsigned)
  841. (wcslen(Domain) + 1) * sizeof(WCHAR), 0));
  842. CALL(JetMakeKey(sesid, sessdirtableid, &one, sizeof(one), 0));
  843. }
  844. else {
  845. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "AllSessionIndex"));
  846. CALL(JetMakeKey(sesid, sessdirtableid, UserName, (unsigned)
  847. (wcslen(UserName) + 1) * sizeof(WCHAR), JET_bitNewKey));
  848. CALL(JetMakeKey(sesid, sessdirtableid, Domain, (unsigned)
  849. (wcslen(Domain) + 1) * sizeof(WCHAR), 0));
  850. }
  851. err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange);
  852. while ((i < TSSD_MaxDisconnectedSessions) && (JET_errSuccess == err)) {
  853. // Remember the initial retrieval does not have cluster id in the
  854. // index, so filter by cluster id for each one.
  855. // Get the ServerID for this record.
  856. CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
  857. SESSDIR_SERVERID_INTERNAL_INDEX], &ServerID, sizeof(ServerID),
  858. &cbActual, 0, NULL));
  859. // Get the clusterID
  860. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
  861. CALL(JetMakeKey(sesid, servdirtableid, &ServerID, sizeof(ServerID),
  862. JET_bitNewKey));
  863. CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
  864. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  865. SERVDIR_CLUSID_INTERNAL_INDEX], &tempClusterID,
  866. sizeof(tempClusterID), &cbActual, 0, NULL));
  867. // Compare to the passed-in cluster id.
  868. if (tempClusterID == CallingServersClusID) {
  869. // Allocate space.
  870. adsi[i].ServerAddress = (WCHAR *) MIDL_user_allocate(64 *
  871. sizeof(WCHAR));
  872. adsi[i].AppType = (WCHAR *) MIDL_user_allocate(256 * sizeof(WCHAR));
  873. if ((adsi[i].ServerAddress == NULL) || (adsi[i].AppType == NULL)) {
  874. TSDISErrorOut(L"GetUserDisc: Memory alloc failed!\n");
  875. goto HandleError;
  876. }
  877. // ServerAddress comes out of the server table
  878. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  879. SERVDIR_SERVADDR_INTERNAL_INDEX], adsi[i].ServerAddress,
  880. 128, &cbActual, 0, NULL));
  881. // The rest come out of the session directory
  882. // Session ID
  883. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  884. sesdircolumnid[SESSDIR_SESSIONID_INTERNAL_INDEX],
  885. &(adsi[i].SessionID), sizeof(DWORD), &cbActual, 0, NULL));
  886. // TSProtocol
  887. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  888. sesdircolumnid[SESSDIR_TSPROTOCOL_INTERNAL_INDEX],
  889. &(adsi[i].TSProtocol), sizeof(DWORD), &cbActual, 0, NULL));
  890. // Application Type
  891. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  892. sesdircolumnid[SESSDIR_APPTYPE_INTERNAL_INDEX],
  893. adsi[i].AppType, 512, &cbActual, 0, NULL));
  894. // ResolutionWidth
  895. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  896. sesdircolumnid[SESSDIR_RESWIDTH_INTERNAL_INDEX],
  897. &(adsi[i].ResolutionWidth), sizeof(DWORD), &cbActual, 0,
  898. NULL));
  899. // ResolutionHeight
  900. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  901. sesdircolumnid[SESSDIR_RESHEIGHT_INTERNAL_INDEX],
  902. &(adsi[i].ResolutionHeight), sizeof(DWORD), &cbActual, 0,
  903. NULL));
  904. // Color Depth
  905. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  906. sesdircolumnid[SESSDIR_COLORDEPTH_INTERNAL_INDEX],
  907. &(adsi[i].ColorDepth), sizeof(DWORD), &cbActual, 0, NULL));
  908. // CreateTimeLow
  909. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  910. sesdircolumnid[SESSDIR_CTLOW_INTERNAL_INDEX],
  911. &(adsi[i].CreateTimeLow), sizeof(DWORD), &cbActual, 0,
  912. NULL));
  913. // CreateTimeHigh
  914. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  915. sesdircolumnid[SESSDIR_CTHIGH_INTERNAL_INDEX],
  916. &(adsi[i].CreateTimeHigh), sizeof(DWORD), &cbActual, 0,
  917. NULL));
  918. // DisconnectTimeLow
  919. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  920. sesdircolumnid[SESSDIR_DTLOW_INTERNAL_INDEX],
  921. &(adsi[i].DisconnectTimeLow), sizeof(DWORD), &cbActual, 0,
  922. NULL));
  923. // DisconnectTimeHigh
  924. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  925. sesdircolumnid[SESSDIR_DTHIGH_INTERNAL_INDEX],
  926. &(adsi[i].DisconnectTimeHigh), sizeof(DWORD), &cbActual, 0,
  927. NULL));
  928. // State
  929. // This is retrieving a byte that is 0xff or 0x0 into a DWORD
  930. // pointer.
  931. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  932. sesdircolumnid[SESSDIR_STATE_INTERNAL_INDEX],
  933. &(adsi[i].State), sizeof(BYTE), &cbActual, 0,
  934. NULL));
  935. i += 1;
  936. }
  937. // Move to the next matching record.
  938. err = JetMove(sesid, sessdirtableid, JET_MoveNext, 0);
  939. }
  940. *pNumSessions = i;
  941. CALL(JetCommitTransaction(sesid, 0));
  942. CALL(JetCloseTable(sesid, servdirtableid));
  943. CALL(JetCloseTable(sesid, sessdirtableid));
  944. CALL(JetCloseTable(sesid, clusdirtableid));
  945. CALL(JetCloseDatabase(sesid, dbid, 0));
  946. CALL(JetEndSession(sesid, 0));
  947. #ifdef DBG
  948. OutputAllTables();
  949. #endif // DBG
  950. return 0;
  951. HandleError:
  952. // Deallocate memory.
  953. if (adsi != NULL) {
  954. for (j = 0; j < TSSD_MaxDisconnectedSessions; j++) {
  955. if (adsi[j].ServerAddress)
  956. MIDL_user_free(adsi[j].ServerAddress);
  957. if (adsi[j].AppType)
  958. MIDL_user_free(adsi[j].AppType);
  959. }
  960. }
  961. // Can't really recover. Just bail out.
  962. if (sesid != JET_sesidNil) {
  963. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  964. // Force the session closed.
  965. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  966. }
  967. TSDISErrorOut(L"WARNING: TSSDRpcGetUserDisconnectedSessions() initiate TSSDPurgeServer()\n");
  968. // Delete the server and close the context handle. Their states are bad.
  969. TSSDPurgeServer(PtrToUlong(*hCI));
  970. *hCI = NULL;
  971. return (DWORD) E_FAIL;
  972. }
  973. /****************************************************************************/
  974. // TSSDRpcCreateSession
  975. //
  976. // Called on a session logon.
  977. /****************************************************************************/
  978. DWORD TSSDRpcCreateSession(
  979. handle_t Binding,
  980. HCLIENTINFO *hCI,
  981. WCHAR __RPC_FAR *UserName,
  982. WCHAR __RPC_FAR *Domain,
  983. DWORD SessionID,
  984. DWORD TSProtocol,
  985. WCHAR __RPC_FAR *AppType,
  986. DWORD ResolutionWidth,
  987. DWORD ResolutionHeight,
  988. DWORD ColorDepth,
  989. DWORD CreateTimeLow,
  990. DWORD CreateTimeHigh)
  991. {
  992. JET_ERR err;
  993. JET_SESID sesid = JET_sesidNil;
  994. JET_DBID dbid;
  995. JET_TABLEID sessdirtableid;
  996. JET_TABLEID servdirtableid;
  997. JET_SETCOLUMN scSessDir[NUM_SESSDIRCOLUMNS];
  998. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  999. unsigned count;
  1000. int zero = 0;
  1001. unsigned long cbActual;
  1002. char state = 0;
  1003. long numDeletedSession = 0;
  1004. // "unreferenced" parameter (referenced by RPC)
  1005. Binding;
  1006. TSDISErrorOut(L"Inside TSSDRpcCreateSession, ServID=%d, "
  1007. L"UserName=%s, Domain=%s, SessID=%d, TSProt=%d, AppType=%s, "
  1008. L"ResWidth=%d, ResHeight=%d, ColorDepth=%d\n", *pCI, UserName,
  1009. Domain, SessionID, TSProtocol, AppType, ResolutionWidth,
  1010. ResolutionHeight, ColorDepth);
  1011. TSDISErrorTimeOut(L" CreateTime=%s\n", CreateTimeLow, CreateTimeHigh);
  1012. memset(&scSessDir[0], 0, sizeof(JET_SETCOLUMN) * NUM_SESSDIRCOLUMNS);
  1013. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  1014. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  1015. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  1016. &sessdirtableid));
  1017. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  1018. &servdirtableid));
  1019. CALL(JetBeginTransaction(sesid));
  1020. // Verify that the ServerID passed in was OK.
  1021. if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
  1022. TSDISErrorOut(L"Invalid ServerID was passed in\n");
  1023. goto HandleError;
  1024. }
  1025. numDeletedSession = DeleteExistingServerSession( sesid, sessdirtableid, pCI, SessionID );
  1026. if( numDeletedSession < 0 ) {
  1027. goto HandleError;
  1028. }
  1029. err = JetMove(sesid, sessdirtableid, JET_MoveLast, 0);
  1030. CALL(JetPrepareUpdate(sesid, sessdirtableid, JET_prepInsert));
  1031. for (count = 0; count < NUM_SESSDIRCOLUMNS; count++) {
  1032. scSessDir[count].columnid = sesdircolumnid[count];
  1033. scSessDir[count].cbData = 4; // most of them, set the rest individually
  1034. scSessDir[count].itagSequence = 1;
  1035. }
  1036. scSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].cbData =
  1037. (unsigned) (wcslen(UserName) + 1) * sizeof(WCHAR);
  1038. scSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].cbData =
  1039. (unsigned) (wcslen(Domain) + 1) * sizeof(WCHAR);
  1040. scSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].cbData =
  1041. (unsigned) (wcslen(AppType) + 1) * sizeof(WCHAR);
  1042. scSessDir[SESSDIR_STATE_INTERNAL_INDEX].cbData = sizeof(char);
  1043. scSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].pvData = UserName;
  1044. scSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].pvData = Domain;
  1045. scSessDir[SESSDIR_SERVERID_INTERNAL_INDEX].pvData = pCI;
  1046. scSessDir[SESSDIR_SESSIONID_INTERNAL_INDEX].pvData = &SessionID;
  1047. scSessDir[SESSDIR_TSPROTOCOL_INTERNAL_INDEX].pvData = &TSProtocol;
  1048. scSessDir[SESSDIR_CTLOW_INTERNAL_INDEX].pvData = &CreateTimeLow;
  1049. scSessDir[SESSDIR_CTHIGH_INTERNAL_INDEX].pvData = &CreateTimeHigh;
  1050. scSessDir[SESSDIR_DTLOW_INTERNAL_INDEX].pvData = &zero;
  1051. scSessDir[SESSDIR_DTHIGH_INTERNAL_INDEX].pvData = &zero;
  1052. scSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].pvData = AppType;
  1053. scSessDir[SESSDIR_RESWIDTH_INTERNAL_INDEX].pvData = &ResolutionWidth;
  1054. scSessDir[SESSDIR_RESHEIGHT_INTERNAL_INDEX].pvData = &ResolutionHeight;
  1055. scSessDir[SESSDIR_COLORDEPTH_INTERNAL_INDEX].pvData = &ColorDepth;
  1056. scSessDir[SESSDIR_STATE_INTERNAL_INDEX].pvData = &state;
  1057. CALL(JetSetColumns(sesid, sessdirtableid, scSessDir, NUM_SESSDIRCOLUMNS));
  1058. CALL(JetUpdate(sesid, sessdirtableid, NULL, 0, &cbActual));
  1059. CALL(JetCommitTransaction(sesid, 0));
  1060. CALL(JetCloseTable(sesid, sessdirtableid));
  1061. CALL(JetCloseTable(sesid, servdirtableid));
  1062. CALL(JetCloseDatabase(sesid, dbid, 0));
  1063. CALL(JetEndSession(sesid, 0));
  1064. return 0;
  1065. HandleError:
  1066. if (sesid != JET_sesidNil) {
  1067. // Can't really recover. Just bail out.
  1068. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  1069. // Force the session closed.
  1070. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  1071. }
  1072. TSDISErrorOut(L"WARNING: TSSDRpcCreateSession failed, start TSSDPurgeServer()\n");
  1073. // Delete the server and close the context handle. Their states are bad.
  1074. TSSDPurgeServer(PtrToUlong(*hCI));
  1075. *hCI = NULL;
  1076. return (DWORD) E_FAIL;
  1077. }
  1078. /****************************************************************************/
  1079. // TSSDRpcDeleteSession
  1080. //
  1081. // Called on a session logoff.
  1082. /****************************************************************************/
  1083. DWORD TSSDRpcDeleteSession(
  1084. handle_t Binding,
  1085. HCLIENTINFO *hCI,
  1086. DWORD SessionID)
  1087. {
  1088. JET_ERR err;
  1089. JET_SESID sesid = JET_sesidNil;
  1090. JET_DBID dbid;
  1091. JET_TABLEID sessdirtableid;
  1092. JET_TABLEID servdirtableid;
  1093. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  1094. // "unreferenced" parameter (referenced by RPC)
  1095. Binding;
  1096. TSDISErrorOut(L"In DelSession, ServID=%d, "
  1097. L"SessID=%d\n", *pCI, SessionID);
  1098. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  1099. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  1100. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  1101. &sessdirtableid));
  1102. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  1103. &servdirtableid));
  1104. CALL(JetBeginTransaction(sesid));
  1105. // Verify that the ServerID passed in was OK.
  1106. if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
  1107. TSDISErrorOut(L"Invalid ServerID was passed in\n");
  1108. goto HandleError;
  1109. }
  1110. // Delete all sessions in session directory that have this serverid
  1111. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "primaryIndex"));
  1112. CALL(JetMakeKey(sesid, sessdirtableid, pCI,
  1113. sizeof(*pCI), JET_bitNewKey));
  1114. CALL(JetMakeKey(sesid, sessdirtableid, &SessionID, sizeof(SessionID),
  1115. 0));
  1116. CALL(JetSeek(sesid, sessdirtableid, JET_bitSeekEQ));
  1117. CALL(JetDelete(sesid, sessdirtableid));
  1118. CALL(JetCommitTransaction(sesid, 0));
  1119. CALL(JetCloseTable(sesid, sessdirtableid));
  1120. CALL(JetCloseTable(sesid, servdirtableid));
  1121. CALL(JetCloseDatabase(sesid, dbid, 0));
  1122. CALL(JetEndSession(sesid, 0));
  1123. return 0;
  1124. HandleError:
  1125. if (sesid != JET_sesidNil) {
  1126. // Can't really recover. Just bail out.
  1127. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  1128. // Force the session closed.
  1129. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  1130. }
  1131. TSDISErrorOut(L"WARNING: DelSession can't find ServID=%d SessID=%d, start TSSDPurgeServer()\n", *pCI, SessionID);
  1132. // Delete the server and close the context handle. Their states are bad.
  1133. TSSDPurgeServer(PtrToUlong(*hCI));
  1134. *hCI = NULL;
  1135. return (DWORD) E_FAIL;
  1136. }
  1137. /****************************************************************************/
  1138. // TSSDRpcSetSessionDisconnected
  1139. //
  1140. // Called on a session disconnection.
  1141. /****************************************************************************/
  1142. DWORD TSSDRpcSetSessionDisconnected(
  1143. handle_t Binding,
  1144. HCLIENTINFO *hCI,
  1145. DWORD SessionID,
  1146. DWORD DiscTimeLow,
  1147. DWORD DiscTimeHigh)
  1148. {
  1149. unsigned long cbActual;
  1150. JET_ERR err;
  1151. JET_SESID sesid = JET_sesidNil;
  1152. JET_DBID dbid;
  1153. JET_TABLEID sessdirtableid;
  1154. JET_TABLEID servdirtableid;
  1155. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  1156. char one = 1;
  1157. DWORD rc = (DWORD) E_FAIL;
  1158. // "unreferenced" parameter (referenced by RPC)
  1159. Binding;
  1160. TSDISErrorOut(L"In SetSessDisc, ServID=%d, SessID=%d\n", *pCI, SessionID);
  1161. TSDISErrorTimeOut(L" DiscTime=%s\n", DiscTimeLow, DiscTimeHigh);
  1162. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  1163. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  1164. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  1165. &sessdirtableid));
  1166. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  1167. &servdirtableid));
  1168. CALL(JetBeginTransaction(sesid));
  1169. // Verify that the ServerID passed in was OK.
  1170. if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
  1171. TSDISErrorOut(L"Invalid ServerID was passed in\n");
  1172. goto HandleError;
  1173. }
  1174. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "primaryIndex"));
  1175. // find the record with the serverid, sessionid we are looking for
  1176. CALL(JetMakeKey(sesid, sessdirtableid, pCI, sizeof(DWORD),
  1177. JET_bitNewKey));
  1178. CALL(JetMakeKey(sesid, sessdirtableid, &SessionID, sizeof(DWORD), 0));
  1179. CALL(JetSeek(sesid, sessdirtableid, JET_bitSeekEQ));
  1180. CALL(JetPrepareUpdate(sesid, sessdirtableid, JET_prepReplace));
  1181. CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
  1182. SESSDIR_STATE_INTERNAL_INDEX], &one, sizeof(one), 0, NULL));
  1183. CALL(JetUpdate(sesid, sessdirtableid, NULL, 0, &cbActual));
  1184. CALL(JetCommitTransaction(sesid, 0));
  1185. CALL(JetCloseTable(sesid, sessdirtableid));
  1186. CALL(JetCloseTable(sesid, servdirtableid));
  1187. CALL(JetCloseDatabase(sesid, dbid, 0));
  1188. CALL(JetEndSession(sesid, 0));
  1189. rc = 0;
  1190. return rc;
  1191. HandleError:
  1192. if (sesid != JET_sesidNil) {
  1193. // Can't really recover. Just bail out.
  1194. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  1195. // Force the session closed
  1196. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  1197. }
  1198. TSDISErrorOut(L"WARNING: SetSessDisc can't find ServID=%d SessID=%d, start TSSDPurgeServer()\n", *pCI, SessionID);
  1199. // Delete the server and close the context handle. Their states are bad.
  1200. TSSDPurgeServer(PtrToUlong(*hCI));
  1201. *hCI = NULL;
  1202. return rc;
  1203. }
  1204. /****************************************************************************/
  1205. // TSSDRpcSetSessionReconnected
  1206. //
  1207. // Called on a session reconnection.
  1208. /****************************************************************************/
  1209. DWORD TSSDRpcSetSessionReconnected(
  1210. handle_t Binding,
  1211. HCLIENTINFO *hCI,
  1212. DWORD SessionID,
  1213. DWORD TSProtocol,
  1214. DWORD ResWidth,
  1215. DWORD ResHeight,
  1216. DWORD ColorDepth)
  1217. {
  1218. JET_ERR err;
  1219. JET_SESID sesid = JET_sesidNil;
  1220. JET_DBID dbid;
  1221. JET_TABLEID sessdirtableid;
  1222. JET_TABLEID servdirtableid;
  1223. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  1224. DWORD rc = (DWORD) E_FAIL;
  1225. char zero = 0;
  1226. unsigned long cbActual;
  1227. // "unreferenced" parameter (referenced by RPC)
  1228. Binding;
  1229. TSDISErrorOut(L"In SetSessRec, ServID=%d, SessID=%d, TSProt=%d, "
  1230. L"ResWid=%d, ResHt=%d, ColDepth=%d\n", *pCI,
  1231. SessionID, TSProtocol, ResWidth, ResHeight,
  1232. ColorDepth);
  1233. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  1234. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  1235. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  1236. &sessdirtableid));
  1237. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  1238. &servdirtableid));
  1239. CALL(JetBeginTransaction(sesid));
  1240. // Verify that the ServerID passed in was OK.
  1241. if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
  1242. TSDISErrorOut(L"Invalid ServerID was passed in\n");
  1243. goto HandleError;
  1244. }
  1245. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "primaryIndex"));
  1246. // Find the record with the serverid, sessionid we are looking for.
  1247. CALL(JetMakeKey(sesid, sessdirtableid, pCI, sizeof(DWORD),
  1248. JET_bitNewKey));
  1249. CALL(JetMakeKey(sesid, sessdirtableid, &SessionID, sizeof(DWORD), 0));
  1250. CALL(JetSeek(sesid, sessdirtableid, JET_bitSeekEQ));
  1251. CALL(JetPrepareUpdate(sesid, sessdirtableid, JET_prepReplace));
  1252. CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
  1253. SESSDIR_TSPROTOCOL_INTERNAL_INDEX], &TSProtocol, sizeof(TSProtocol),
  1254. 0, NULL));
  1255. CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
  1256. SESSDIR_RESWIDTH_INTERNAL_INDEX], &ResWidth, sizeof(ResWidth),
  1257. 0, NULL));
  1258. CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
  1259. SESSDIR_RESHEIGHT_INTERNAL_INDEX], &ResHeight, sizeof(ResHeight),
  1260. 0, NULL));
  1261. CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
  1262. SESSDIR_COLORDEPTH_INTERNAL_INDEX], &ColorDepth, sizeof(ColorDepth),
  1263. 0, NULL));
  1264. CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
  1265. SESSDIR_STATE_INTERNAL_INDEX], &zero, sizeof(zero), 0, NULL));
  1266. CALL(JetUpdate(sesid, sessdirtableid, NULL, 0, &cbActual));
  1267. CALL(JetCommitTransaction(sesid, 0));
  1268. CALL(JetCloseTable(sesid, sessdirtableid));
  1269. CALL(JetCloseTable(sesid, servdirtableid));
  1270. CALL(JetCloseDatabase(sesid, dbid, 0));
  1271. CALL(JetEndSession(sesid, 0));
  1272. rc = 0;
  1273. return rc;
  1274. HandleError:
  1275. if (sesid != JET_sesidNil) {
  1276. // Can't really recover. Just bail out.
  1277. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  1278. // Force the session closed.
  1279. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  1280. }
  1281. TSDISErrorOut(L"WARNING: SetSessRec can't find ServID=%d SessID=%d, start TSSDPurgeServer()\n", *pCI, SessionID);
  1282. // Delete the server and close the context handle. Their states are bad.
  1283. TSSDPurgeServer(PtrToUlong(*hCI));
  1284. *hCI = NULL;
  1285. return rc;
  1286. }
  1287. DWORD TSSDRpcSetServerReconnectPending(
  1288. handle_t Binding,
  1289. WCHAR __RPC_FAR *ServerAddress,
  1290. DWORD AlmostTimeLow,
  1291. DWORD AlmostTimeHigh)
  1292. {
  1293. // Ignored parameters
  1294. Binding;
  1295. AlmostTimeLow;
  1296. AlmostTimeHigh;
  1297. return TSSDSetServerAITInternal(ServerAddress, FALSE, NULL);
  1298. }
  1299. /****************************************************************************/
  1300. // TSSDRpcUpdateConfigurationSetting
  1301. //
  1302. // Extensible interface to update a configuration setting.
  1303. /****************************************************************************/
  1304. DWORD TSSDSetServerAddress(HCLIENTINFO *hCI, WCHAR *ServerName)
  1305. {
  1306. JET_ERR err;
  1307. JET_SESID sesid = JET_sesidNil;
  1308. JET_DBID dbid;
  1309. JET_TABLEID servdirtableid;
  1310. unsigned long cbActual;
  1311. WCHAR Msg[SDNAMELENGTH * 2 + 3];
  1312. DWORD rc = (DWORD) E_FAIL;
  1313. TSDISErrorOut(L"INFO: TSSDSetServerAddress ServID=%d, %s\n", *hCI, ServerName);
  1314. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  1315. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  1316. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  1317. &servdirtableid));
  1318. // Find the server in the server directory
  1319. CALL(JetBeginTransaction(sesid));
  1320. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
  1321. CALL(JetMakeKey(sesid, servdirtableid, (const void *)hCI, sizeof(DWORD),
  1322. JET_bitNewKey));
  1323. CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
  1324. // Get the server DNS name
  1325. cbActual = SDNAMELENGTH * sizeof(WCHAR);
  1326. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  1327. SERVDIR_SERVDNSNAME_INTERNAL_INDEX], Msg,
  1328. cbActual, &cbActual, 0, NULL));
  1329. // Prepare to update.
  1330. CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepReplace));
  1331. // Now set the column to what we want
  1332. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1333. SERVDIR_SERVADDR_INTERNAL_INDEX], (void *) ServerName,
  1334. (unsigned) (wcslen(ServerName) + 1) * sizeof(WCHAR), 0,
  1335. NULL));
  1336. CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
  1337. CALL(JetCommitTransaction(sesid, 0));
  1338. // Clean up.
  1339. CALL(JetCloseTable(sesid, servdirtableid));
  1340. CALL(JetCloseDatabase(sesid, dbid, 0));
  1341. CALL(JetEndSession(sesid, 0));
  1342. // Construct log msg to record TS joining SD
  1343. wcscat(Msg, L"(");
  1344. wcsncat(Msg, ServerName, SDNAMELENGTH);
  1345. wcscat(Msg, L")");
  1346. PostSessDirErrorMsgEvent(EVENT_SUCCESS_JOIN_SESSIONDIRECTORY, Msg, EVENTLOG_SUCCESS);
  1347. rc = 0;
  1348. return rc;
  1349. HandleError:
  1350. if (sesid != JET_sesidNil) {
  1351. // Can't really recover. Just bail out.
  1352. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  1353. // Force the session closed
  1354. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  1355. }
  1356. TSDISErrorOut(L"WARNING: TSSDSetServerAddress can't find ServID=%d, start TSSDPurgeServer()\n", *hCI);
  1357. TSSDPurgeServer(PtrToUlong(*hCI));
  1358. // Close the context handle.
  1359. *hCI = NULL;
  1360. return rc;
  1361. }
  1362. /****************************************************************************/
  1363. // TSSDRpcUpdateConfigurationSetting
  1364. //
  1365. // Extensible interface to update a configuration setting.
  1366. /****************************************************************************/
  1367. DWORD TSSDRpcUpdateConfigurationSetting(
  1368. handle_t Binding,
  1369. HCLIENTINFO *hCI,
  1370. DWORD dwSetting,
  1371. DWORD dwSettingLength,
  1372. BYTE __RPC_FAR *pbValue)
  1373. {
  1374. // Unreferenced parameters.
  1375. Binding;
  1376. hCI;
  1377. dwSetting;
  1378. dwSettingLength;
  1379. pbValue;
  1380. if (dwSetting == SDCONFIG_SERVER_ADDRESS) {
  1381. TSDISErrorOut(L"Server is setting its address as %s\n",
  1382. (WCHAR *) pbValue);
  1383. return TSSDSetServerAddress(hCI, (WCHAR *) pbValue);
  1384. }
  1385. return (DWORD) E_NOTIMPL;
  1386. }
  1387. /****************************************************************************/
  1388. // TSSDSetServerAITInternal
  1389. //
  1390. // Called on a client redirection from one server to another, to let the
  1391. // integrity service determine how to ping the redirection target machine.
  1392. //
  1393. // Args:
  1394. // ServerAddress (in) - the server address to set values for
  1395. // bResetToZero (in) - whether to reset all AIT values to 0
  1396. // FailureCount (in/out) - Pointer to nonzero on entry means increment the
  1397. // failure count. Returns the result failure count.
  1398. /****************************************************************************/
  1399. DWORD TSSDSetServerAITInternal(
  1400. WCHAR *ServerAddress,
  1401. DWORD bResetToZero,
  1402. DWORD *FailureCount)
  1403. {
  1404. JET_ERR err;
  1405. JET_SESID sesid = JET_sesidNil;
  1406. JET_DBID dbid;
  1407. JET_TABLEID servdirtableid;
  1408. DWORD AITFromServDirLow;
  1409. DWORD AITFromServDirHigh;
  1410. unsigned long cbActual;
  1411. DWORD rc = (DWORD) E_FAIL;
  1412. TSDISErrorOut(L"SetServAITInternal: ServAddr=%s, bResetToZero=%d, bIncFail"
  1413. L"=%d\n", ServerAddress, bResetToZero, (FailureCount == NULL) ?
  1414. 0 : *FailureCount);
  1415. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  1416. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  1417. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  1418. &servdirtableid));
  1419. CALL(JetBeginTransaction(sesid));
  1420. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServNameIndex"));
  1421. CALL(JetMakeKey(sesid, servdirtableid, ServerAddress, (unsigned)
  1422. (wcslen(ServerAddress) + 1) * sizeof(WCHAR), JET_bitNewKey));
  1423. CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
  1424. // Algorithm for set reconnect pending:
  1425. // 1) If server is not already pending a reconnect,
  1426. // 2) Set the AlmostTimeLow and High to locally computed times (using
  1427. // the times from the wire is dangerous and requires clocks to be the
  1428. // same).
  1429. // Retrieve the current values of AlmostInTimeLow and High
  1430. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  1431. SERVDIR_AITLOW_INTERNAL_INDEX], &AITFromServDirLow,
  1432. sizeof(AITFromServDirLow), &cbActual, 0, NULL));
  1433. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  1434. SERVDIR_AITHIGH_INTERNAL_INDEX], &AITFromServDirHigh,
  1435. sizeof(AITFromServDirHigh), &cbActual, 0, NULL));
  1436. // If it's time to reset, reset to 0.
  1437. if (bResetToZero != 0) {
  1438. DWORD zero = 0;
  1439. CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepReplace));
  1440. // Set the columns: Low, High, and NumFailedPings.
  1441. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1442. SERVDIR_AITLOW_INTERNAL_INDEX], &zero, sizeof(zero), 0, NULL));
  1443. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1444. SERVDIR_AITHIGH_INTERNAL_INDEX], &zero, sizeof(zero), 0, NULL));
  1445. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1446. SERVDIR_NUMFAILPINGS_INTERNAL_INDEX], &zero, sizeof(zero), 0,
  1447. NULL));
  1448. CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
  1449. }
  1450. // Otherwise, if the server isn't already pending a reconnect,
  1451. else if ((AITFromServDirLow == 0) && (AITFromServDirHigh == 0)) {
  1452. FILETIME ft;
  1453. SYSTEMTIME st;
  1454. // Retrieve the time.
  1455. GetSystemTime(&st);
  1456. SystemTimeToFileTime(&st, &ft);
  1457. err = JetPrepareUpdate(sesid, servdirtableid, JET_prepReplace);
  1458. if (JET_errWriteConflict == err) {
  1459. // If we are here, it's that more than two threads are updating the time
  1460. // field at the same time. Since we only need to update it once, so just
  1461. // bail out the other ones, but still return success
  1462. rc = 0;
  1463. goto HandleError;
  1464. }
  1465. else {
  1466. CALL(err);
  1467. }
  1468. // Set the columns.
  1469. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1470. SERVDIR_AITLOW_INTERNAL_INDEX], &(ft.dwLowDateTime),
  1471. sizeof(ft.dwLowDateTime), 0, NULL));
  1472. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1473. SERVDIR_AITHIGH_INTERNAL_INDEX], &(ft.dwHighDateTime),
  1474. sizeof(ft.dwHighDateTime), 0, NULL));
  1475. CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
  1476. }
  1477. // Else if we were told to increment the failure count
  1478. else if (FailureCount != NULL) {
  1479. if (*FailureCount != 0) {
  1480. DWORD FailureCountFromServDir;
  1481. // Get the current failure count.
  1482. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  1483. SERVDIR_NUMFAILPINGS_INTERNAL_INDEX],
  1484. &FailureCountFromServDir, sizeof(FailureCountFromServDir),
  1485. &cbActual, 0, NULL));
  1486. // Set return value, also value used for update.
  1487. *FailureCount = FailureCountFromServDir + 1;
  1488. CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepReplace));
  1489. // Set the column.
  1490. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1491. SERVDIR_NUMFAILPINGS_INTERNAL_INDEX],
  1492. FailureCount, sizeof(*FailureCount), 0, NULL));
  1493. CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
  1494. }
  1495. }
  1496. CALL(JetCommitTransaction(sesid, 0));
  1497. CALL(JetCloseTable(sesid, servdirtableid));
  1498. CALL(JetCloseDatabase(sesid, dbid, 0));
  1499. CALL(JetEndSession(sesid, 0));
  1500. rc = 0;
  1501. return rc;
  1502. HandleError:
  1503. if (sesid != JET_sesidNil) {
  1504. // Can't really recover. Just bail out.
  1505. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  1506. // Force the session closed
  1507. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  1508. }
  1509. return rc;
  1510. }
  1511. DWORD TSSDRpcRepopulateAllSessions(
  1512. handle_t Binding,
  1513. HCLIENTINFO *hCI,
  1514. DWORD NumSessions,
  1515. TSSD_RepopInfo rpi[])
  1516. {
  1517. JET_ERR err;
  1518. JET_SESID sesid = JET_sesidNil;
  1519. JET_DBID dbid;
  1520. JET_TABLEID sessdirtableid;
  1521. JET_TABLEID servdirtableid;
  1522. JET_SETCOLUMN scSessDir[NUM_SESSDIRCOLUMNS];
  1523. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  1524. unsigned count; // inside each record
  1525. unsigned iCurrSession;
  1526. unsigned long cbActual;
  1527. char State;
  1528. DWORD rc = (DWORD) E_FAIL;
  1529. long numDeletedSession = 0;
  1530. // "unreferenced" parameter (referenced by RPC)
  1531. Binding;
  1532. TSDISErrorOut(L"RepopAllSess: ServID = %d, NumSessions = %d, ...\n",
  1533. *pCI, NumSessions);
  1534. memset(&scSessDir[0], 0, sizeof(JET_SETCOLUMN) * NUM_SESSDIRCOLUMNS);
  1535. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  1536. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  1537. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  1538. &sessdirtableid));
  1539. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  1540. &servdirtableid));
  1541. CALL(JetBeginTransaction(sesid));
  1542. // Verify that the ServerID passed in was OK.
  1543. if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
  1544. TSDISErrorOut(L"Invalid ServerID was passed in\n");
  1545. goto HandleError;
  1546. }
  1547. // Set up some constants for all updates.
  1548. for (count = 0; count < NUM_SESSDIRCOLUMNS; count++) {
  1549. scSessDir[count].columnid = sesdircolumnid[count];
  1550. scSessDir[count].cbData = 4; // most of them, set the rest individually
  1551. scSessDir[count].itagSequence = 1;
  1552. }
  1553. scSessDir[SESSDIR_STATE_INTERNAL_INDEX].cbData = sizeof(char);
  1554. // Now do each update in a loop.
  1555. for (iCurrSession = 0; iCurrSession < NumSessions; iCurrSession += 1) {
  1556. // make sure session does not exist at this point
  1557. numDeletedSession = DeleteExistingServerSession( sesid, sessdirtableid, pCI, rpi[iCurrSession].SessionID );
  1558. if( numDeletedSession < 0 ) {
  1559. goto HandleError;
  1560. }
  1561. err = JetMove(sesid, sessdirtableid, JET_MoveLast, 0);
  1562. CALL(JetPrepareUpdate(sesid, sessdirtableid, JET_prepInsert));
  1563. TSDISErrorOut(L"RepopAllSess: ServID = %d, SessionId = %d, %s %s...\n",
  1564. *pCI,
  1565. rpi[iCurrSession].SessionID,
  1566. rpi[iCurrSession].UserName,
  1567. rpi[iCurrSession].Domain
  1568. );
  1569. ASSERT( (wcslen(rpi[iCurrSession].UserName) > 0), (TB, "NULL User Name...") );
  1570. ASSERT( (wcslen(rpi[iCurrSession].Domain) > 0), (TB, "NULL Domain Name...") );
  1571. scSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].cbData =
  1572. (unsigned) (wcslen(rpi[iCurrSession].UserName) + 1) *
  1573. sizeof(WCHAR);
  1574. scSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].cbData =
  1575. (unsigned) (wcslen(rpi[iCurrSession].Domain) + 1) *
  1576. sizeof(WCHAR);
  1577. scSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].cbData =
  1578. (unsigned) (wcslen(rpi[iCurrSession].AppType) + 1) *
  1579. sizeof(WCHAR);
  1580. scSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].pvData =
  1581. rpi[iCurrSession].UserName;
  1582. scSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].pvData =
  1583. rpi[iCurrSession].Domain;
  1584. scSessDir[SESSDIR_SERVERID_INTERNAL_INDEX].pvData = pCI;
  1585. scSessDir[SESSDIR_SESSIONID_INTERNAL_INDEX].pvData =
  1586. &rpi[iCurrSession].SessionID;
  1587. scSessDir[SESSDIR_TSPROTOCOL_INTERNAL_INDEX].pvData =
  1588. &rpi[iCurrSession].TSProtocol;
  1589. scSessDir[SESSDIR_CTLOW_INTERNAL_INDEX].pvData =
  1590. &rpi[iCurrSession].CreateTimeLow;
  1591. scSessDir[SESSDIR_CTHIGH_INTERNAL_INDEX].pvData =
  1592. &rpi[iCurrSession].CreateTimeHigh;
  1593. scSessDir[SESSDIR_DTLOW_INTERNAL_INDEX].pvData =
  1594. &rpi[iCurrSession].DisconnectTimeLow;
  1595. scSessDir[SESSDIR_DTHIGH_INTERNAL_INDEX].pvData =
  1596. &rpi[iCurrSession].DisconnectTimeHigh;
  1597. scSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].pvData =
  1598. rpi[iCurrSession].AppType;
  1599. scSessDir[SESSDIR_RESWIDTH_INTERNAL_INDEX].pvData =
  1600. &rpi[iCurrSession].ResolutionWidth;
  1601. scSessDir[SESSDIR_RESHEIGHT_INTERNAL_INDEX].pvData =
  1602. &rpi[iCurrSession].ResolutionHeight;
  1603. scSessDir[SESSDIR_COLORDEPTH_INTERNAL_INDEX].pvData =
  1604. &rpi[iCurrSession].ColorDepth;
  1605. State = (char) rpi[iCurrSession].State;
  1606. scSessDir[SESSDIR_STATE_INTERNAL_INDEX].pvData = &State;
  1607. CALL(JetSetColumns(sesid, sessdirtableid, scSessDir,
  1608. NUM_SESSDIRCOLUMNS));
  1609. CALL(JetUpdate(sesid, sessdirtableid, NULL, 0, &cbActual));
  1610. }
  1611. CALL(JetCommitTransaction(sesid, 0));
  1612. CALL(JetCloseTable(sesid, sessdirtableid));
  1613. CALL(JetCloseTable(sesid, servdirtableid));
  1614. CALL(JetCloseDatabase(sesid, dbid, 0));
  1615. CALL(JetEndSession(sesid, 0));
  1616. rc = 0;
  1617. return rc;
  1618. HandleError:
  1619. if (sesid != JET_sesidNil) {
  1620. // Can't really recover. Just bail out.
  1621. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  1622. // Force the session closed
  1623. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  1624. }
  1625. TSDISErrorOut(L"WARNING: TSSDRpcRepopulateAllSessions failed, ServID=%d\n", *pCI);
  1626. return rc;
  1627. }
  1628. //
  1629. // RPC call that caller uses to see if it have access to Session Directory
  1630. //
  1631. DWORD TSSDRpcPingSD(handle_t Binding)
  1632. {
  1633. Binding;
  1634. // RPC Security check is done at SDRPCAccessCheck() before this
  1635. // function is hit, just return RPC_S_OK
  1636. TRC1((TB,"Somebody calls pint sd"));
  1637. return RPC_S_OK;
  1638. }
  1639. // Called to determine whether a ServerID passed in is valid. TRUE if valid,
  1640. // FALSE otherwise.
  1641. //
  1642. // Must be inside a transaction, and sesid and servdirtableid must be ready to
  1643. // go.
  1644. BOOL TSSDVerifyServerIDValid(JET_SESID sesid, JET_TABLEID servdirtableid,
  1645. DWORD ServerID)
  1646. {
  1647. JET_ERR err;
  1648. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
  1649. CALL(JetMakeKey(sesid, servdirtableid, (const void *) &ServerID,
  1650. sizeof(DWORD), JET_bitNewKey));
  1651. // If the ServerID is there, this will succeed, otherwise it will fail and
  1652. // jump to HandleError.
  1653. CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
  1654. return TRUE;
  1655. HandleError:
  1656. return FALSE;
  1657. }
  1658. // Rundown procedure for when a CLIENTINFO is destroyed as a result of a
  1659. // connection loss or client termination.
  1660. void HCLIENTINFO_rundown(HCLIENTINFO hCI)
  1661. {
  1662. CLIENTINFO CI = PtrToUlong(hCI);
  1663. TSDISErrorOut(L"WARNING: In HCLIENTINFO_rundown: ServerID=%d\n", CI);
  1664. if (CI != NULL)
  1665. TSSDPurgeServer(CI);
  1666. hCI = NULL;
  1667. }
  1668. #pragma warning (pop)