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.

644 lines
20 KiB

  1. // Session.cpp : This file contains the
  2. // Created: Feb '98
  3. // Author : a-rakeba
  4. // History:
  5. // Copyright (C) 1998 Microsoft Corporation
  6. // All rights reserved.
  7. // Microsoft Confidential
  8. #include <cmnhdr.h>
  9. #include <debug.h>
  10. #include <lmaccess.h>
  11. #include <lmapibuf.h>
  12. #include <lmerr.h>
  13. #include <lmwksta.h>
  14. #include <MsgFile.h>
  15. #include <Telnetd.h>
  16. #include <Session.h>
  17. #include <TlntUtils.h>
  18. #include <RegUtil.h>
  19. #pragma warning( disable: 4127 )
  20. #pragma warning( disable: 4706 )
  21. using namespace _Utils;
  22. using CDebugLevel::TRACE_DEBUGGING;
  23. using CDebugLevel::TRACE_HANDLE;
  24. using CDebugLevel::TRACE_SOCKET;
  25. extern HANDLE g_hSyncCloseHandle;
  26. CSession::CSession() : CIoHandler(), CRFCProtocol(), CShell(), CScraper()
  27. {
  28. m_bNtVersionGTE5 = false;
  29. m_dwTickCountAtLogon = 0;
  30. m_wNumFailedLogins = 0;
  31. m_bContinueSession = true;
  32. m_dwHandleCount = 0;
  33. m_wIsAnAdmin = DONT_KNOW;
  34. m_bIsStreamMode = false;
  35. m_bIsTelnetClientsGroupMember = false;
  36. m_hLogHandle = NULL;
  37. m_hToken = NULL;
  38. m_bIsTelnetVersion2 = false;
  39. m_AuthenticationId.HighPart = m_AuthenticationId.LowPart = 0;
  40. m_pszTermType[0] = 0;
  41. m_bNegotiatedTermType = false;
  42. m_wCols = DEFAULT_COLS;
  43. m_wRows = DEFAULT_ROWS;
  44. m_dwAllowTrustedDomain = DEFAULT_ALLOW_TRUSTED_DOMAIN;
  45. m_dwIdleSessionTimeOut = DEFAULT_IDLE_SESSION_TIME_OUT;
  46. m_pszDefaultDomain = NULL;
  47. m_pszDefaultShell = NULL;
  48. m_pszDifferentShell = NULL;
  49. m_pszSwitchToKeepShellRunning = NULL;
  50. m_pszSwitchForOneTimeUseOfShell = NULL;
  51. m_pszLoginScript = NULL;
  52. m_dwNTLMSetting = DEFAULT_SECURITY_MECHANISM;
  53. m_dwMaxFailedLogins = DEFAULT_MAX_FAILED_LOGINS;
  54. m_dwSysAuditing = DEFAULT_SYSAUDITING;
  55. m_dwLogEvents = DEFAULT_LOGEVENTS;
  56. m_dwLogAdmin = DEFAULT_LOGADMIN;
  57. m_dwLogFailures = DEFAULT_LOGFAILURES;
  58. m_dwLogToFile = DEFAULT_LOGTOFILE;
  59. m_pszUserName[0] = 0;
  60. m_szMachineName[0] = 0;
  61. m_szPeerHostName[0] = 0;
  62. m_szUser[0] = L'\0';
  63. m_szDomain[0] = L'\0';
  64. administrators = pTelnetClientsSid = NULL;
  65. }
  66. void
  67. CSession::FreeInitialVariables()
  68. {
  69. CShell::FreeInitialVariables();
  70. delete [] m_pszDifferentShell;
  71. delete [] m_pszDefaultDomain;
  72. delete [] m_pszDefaultShell;
  73. delete [] m_pszSwitchForOneTimeUseOfShell;
  74. delete [] m_pszSwitchToKeepShellRunning;
  75. delete [] m_pszLoginScript;
  76. m_pszDefaultDomain = NULL;
  77. m_pszSwitchForOneTimeUseOfShell = NULL;
  78. m_pszDefaultShell = NULL;
  79. m_pszSwitchToKeepShellRunning = NULL;
  80. m_pszLoginScript = NULL;
  81. m_pszDifferentShell = NULL;
  82. }
  83. CSession::~CSession()
  84. {
  85. FreeInitialVariables();
  86. FreeSid(administrators);
  87. delete pTelnetClientsSid;
  88. TELNET_CLOSE_HANDLE( m_hToken );
  89. }
  90. bool
  91. CSession::Init()
  92. {
  93. // get a handle to log events with
  94. _chVERIFY2( m_hLogHandle = RegisterEventSource(NULL, L"TlntSvr" ) );
  95. //Get the registry values from HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\TelnetServer
  96. if( !GetRegistryValues( ) )
  97. {
  98. return( FALSE );
  99. }
  100. if( !CIoHandler::Init( this ) )
  101. {
  102. return( FALSE );
  103. }
  104. CShell::Init( this );
  105. CRFCProtocol::Init( this );
  106. CScraper::Init( this );
  107. SetLastError( 0 );
  108. AddHandleToWaitOn( CIoHandler::m_oReadFromPipe.hEvent );
  109. if( !CIoHandler::IssueFirstReadOnPipe() )
  110. {
  111. return( FALSE );
  112. }
  113. CScraper::m_dwPollInterval = PRE_SESSION_STATE_TIMEOUT;
  114. return ( TRUE );
  115. }
  116. void
  117. CSession::AddHandleToWaitOn( HANDLE hNew )
  118. {
  119. _chASSERT( m_dwHandleCount < MAX_HANDLES );
  120. _chASSERT( hNew );
  121. m_rghHandlestoWaitOn[ m_dwHandleCount ] = hNew;
  122. m_dwHandleCount++;
  123. }
  124. #define HALF_K 512
  125. void
  126. CSession::WaitForIo()
  127. {
  128. DWORD dwRetVal = WAIT_FAILED;
  129. char szMessageBuffer[HALF_K + 1];
  130. while( m_bContinueSession )
  131. {
  132. dwRetVal = WaitForMultipleObjects(m_dwHandleCount,
  133. m_rghHandlestoWaitOn, FALSE, CScraper::m_dwPollInterval );
  134. switch( dwRetVal )
  135. {
  136. case PIPE_READ :
  137. m_bContinueSession =
  138. CIoHandler::OnReadFromPipeCompletion();
  139. break;
  140. case SOCKET_READ:
  141. m_bContinueSession =
  142. CIoHandler::OnReadFromSocketCompletion();
  143. break;
  144. case CMD_KILLED:
  145. m_bContinueSession = false;
  146. break;
  147. case READ_FROM_CMD :
  148. m_dwPollInterval = MIN_POLL_INTERVAL;
  149. m_bContinueSession = CShell::OnDataFromCmdPipe();
  150. break;
  151. case WAIT_TIMEOUT:
  152. if( CIoHandler::m_SocketControlState == STATE_AUTH_NAME
  153. || CIoHandler::m_SocketControlState == STATE_AUTH_PASSWORD )
  154. {
  155. DWORD dwNumBytesWritten = 0;
  156. _snprintf( szMessageBuffer, HALF_K, "\r\n%s\r\n%s", TIMEOUT_STR, TERMINATE );
  157. CIoHandler::SendTerminateString(szMessageBuffer);
  158. CIoHandler::WriteToClient( );
  159. FinishIncompleteIo( ( HANDLE ) CIoHandler::m_sSocket,
  160. &( CIoHandler::m_oWriteToSocket) , &dwNumBytesWritten );
  161. m_bContinueSession = false;
  162. }
  163. else
  164. {
  165. m_bContinueSession = CScraper::OnWaitTimeOut();
  166. if( m_bContinueSession )
  167. {
  168. m_bContinueSession = ( CScraper::IsSessionTimedOut() == false );
  169. }
  170. }
  171. break;
  172. default:
  173. //incase WAIT_FAILED, call GetLastError()
  174. _chVERIFY2( dwRetVal != WAIT_FAILED );
  175. m_bContinueSession = false;
  176. }
  177. }
  178. return;
  179. }
  180. void
  181. CSession::CollectPeerInfo ()
  182. {
  183. m_dwTickCountAtLogon = GetTickCount();
  184. INT len = sizeof( m_ssPeerAddress );
  185. TCHAR szDebugString[500];
  186. if( getpeername(CIoHandler::m_sSocket, (struct sockaddr *) &m_ssPeerAddress,
  187. &len) == SOCKET_ERROR )
  188. {
  189. _TRACE( TRACE_DEBUGGING, "Error: getpeername() : %lu", GetLastError() );
  190. }
  191. if( getnameinfo((SOCKADDR*)&m_ssPeerAddress, len, CSession::m_szPeerHostName, sizeof(CSession::m_szPeerHostName)-1,
  192. NULL, 0, NI_NUMERICHOST)
  193. )
  194. {
  195. _TRACE( TRACE_DEBUGGING, "Error: getnameinfo() : %d", (DWORD)GetLastError() );
  196. }
  197. else
  198. {
  199. _TRACE(TRACE_DEBUGGING, "getnameinfo() : %s",CSession::m_szPeerHostName);
  200. }
  201. if(getnameinfo((SOCKADDR*)&m_ssPeerAddress, len, m_szMachineName, sizeof(m_szMachineName)-1,
  202. NULL, 0, 0)
  203. )
  204. {
  205. _TRACE( TRACE_DEBUGGING, "Error: getnameinfo() - machinename : %d", (DWORD)GetLastError() );
  206. strcpy( m_szMachineName, "" ); // No Attack :-) Baskar
  207. }
  208. else
  209. {
  210. _TRACE(TRACE_DEBUGGING, "getnameinfo() - machinename : %s",m_szMachineName);
  211. }
  212. return;
  213. }
  214. bool
  215. CSession::GetRegistryValues()
  216. {
  217. DWORD dwRetVal;
  218. HKEY hk = NULL;
  219. DWORD dwDisp = 0;
  220. if( dwRetVal = TnSecureRegCreateKeyEx( HKEY_LOCAL_MACHINE, REG_PARAMS_KEY, NULL, NULL,
  221. REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED , NULL, &hk, &dwDisp, 0) )
  222. {
  223. _TRACE( TRACE_DEBUGGING, "Error: RegCreateKey() -- 0x%1x", dwRetVal);
  224. LogEvent( EVENTLOG_ERROR_TYPE, MSG_REGISTRYKEY, REG_PARAMS_KEY );
  225. return ( FALSE );
  226. }
  227. if( !GetRegistryDW( hk, NULL, L"MaxFailedLogins", &m_dwMaxFailedLogins,
  228. DEFAULT_MAX_FAILED_LOGINS,FALSE ) )
  229. {
  230. return false;
  231. }
  232. if( !GetRegistryDW( hk, NULL, L"AllowTrustedDomain", &m_dwAllowTrustedDomain,
  233. DEFAULT_ALLOW_TRUSTED_DOMAIN,FALSE ) )
  234. {
  235. return false;
  236. }
  237. if( !GetRegistryDW( hk, NULL, L"SecurityMechanism", &m_dwNTLMSetting,
  238. DEFAULT_SECURITY_MECHANISM,FALSE ) )
  239. {
  240. return false;
  241. }
  242. if( !GetRegistryDW( hk, NULL, L"LogToFile", &m_dwLogToFile,
  243. DEFAULT_LOGTOFILE,FALSE ) )
  244. {
  245. return false;
  246. }
  247. if( !GetRegistryDW( hk, NULL, L"EventLoggingEnabled", &m_dwSysAuditing,
  248. DEFAULT_SYSAUDITING,FALSE ) )
  249. {
  250. return false;
  251. }
  252. if( !GetRegistryDW( hk, NULL, L"LogNonAdminAttempts", &m_dwLogEvents,
  253. DEFAULT_LOGEVENTS,FALSE ) )
  254. {
  255. return false;
  256. }
  257. if( !GetRegistryDW( hk, NULL, L"LogAdminAttempts", &m_dwLogAdmin,
  258. DEFAULT_LOGADMIN,FALSE ) )
  259. {
  260. return false;
  261. }
  262. if( !GetRegistryDW( hk, NULL, L"LogFailures", &m_dwLogFailures,
  263. DEFAULT_LOGFAILURES,FALSE ) )
  264. {
  265. return false;
  266. }
  267. DWORD dwModeOfOperation = DEFAULT_MODE_OF_OPERATION;
  268. DWORD dwKillAllApps;
  269. if( !GetRegistryDW( hk, NULL, L"AltKeyMapping", &m_dwAltKeyMapping,
  270. DEFAULT_ALT_KEY_MAPPING,FALSE ) )
  271. {
  272. return false;
  273. }
  274. if( !GetRegistryDW( hk, NULL, L"IdleSessionTimeOut", &m_dwIdleSessionTimeOut,
  275. DEFAULT_IDLE_SESSION_TIME_OUT,FALSE ) )
  276. {
  277. return false;
  278. }
  279. if( !GetRegistryDW( hk, NULL, L"DisconnectKillAllApps", &dwKillAllApps,
  280. DEFAULT_DISCONNECT_KILLALL_APPS,FALSE ) )
  281. {
  282. return false;
  283. }
  284. if( !GetRegistryDW( hk, NULL, L"ModeOfOperation", &dwModeOfOperation,
  285. DEFAULT_MODE_OF_OPERATION,FALSE ) )
  286. {
  287. return false;
  288. }
  289. m_bIsStreamMode = false;
  290. if( dwModeOfOperation == STREAM_MODE )
  291. {
  292. m_bIsStreamMode = true;
  293. }
  294. if( !GetRegistryString( hk, NULL, L"DefaultShell", &m_pszDefaultShell,
  295. DEFAULT_SHELL,FALSE ) )
  296. {
  297. return false;
  298. }
  299. if( !GetRegistryString( hk, NULL, SWITCH_TO_KEEP_SHELL_RUNNING,
  300. &m_pszSwitchToKeepShellRunning,
  301. DEFAULT_SWITCH_TO_KEEP_SHELL_RUNNING ,FALSE) )
  302. {
  303. return false;
  304. }
  305. if( !GetRegistryString( hk, NULL, SWITCH_FOR_ONE_TIME_USE_OF_SHELL,
  306. &m_pszSwitchForOneTimeUseOfShell,
  307. DEFAULT_SWITCH_FOR_ONE_TIME_USE_OF_SHELL,FALSE ) )
  308. {
  309. return false;
  310. }
  311. if( !GetRegistryString( hk, NULL, L"Shell", &m_pszDifferentShell, L"",FALSE ) )
  312. {
  313. return false;
  314. }
  315. //When server comes up it creates all keys. So, assume they are available.
  316. //Default values need not be correct as in the case of following.
  317. if( !GetRegistryString( hk, NULL, L"LoginScript", &m_pszLoginScript, L"",FALSE ) )
  318. {
  319. return false;
  320. }
  321. if( !GetRegistryString( hk, NULL, L"DefaultDomain", &m_pszDefaultDomain,
  322. DEFAULT_DOMAIN,FALSE ) )
  323. {
  324. return false;
  325. }
  326. RegCloseKey( hk );
  327. if( !GetWindowsVersion( &m_bNtVersionGTE5 ) )
  328. {
  329. return( FALSE );
  330. }
  331. return( TRUE );
  332. }
  333. #ifdef LOGGING_ENABLED
  334. //This function logs the logon/logoff details as opted by the user.
  335. //This function can be furthur optimized by using the values calculated at logon
  336. //at the time of logoff.
  337. void
  338. CSession::LogIfOpted( BOOL result, LOGEVENT logon, BOOL bNTLMAuth )
  339. {
  340. LPWSTR wideLogStr;
  341. UCHAR *logStr;
  342. BOOL isAdmin = false;
  343. if( result == LOGOFF && !m_dwLogFailures )
  344. {
  345. return;
  346. }
  347. if ( result == LOGON && !m_dwLogAdmin && !m_dwLogEvents)
  348. {
  349. return;
  350. }
  351. if ( result == LOGON && ( m_dwLogAdmin || m_dwLogEvents ) )
  352. {
  353. if( m_wIsAnAdmin == DONT_KNOW )
  354. {
  355. IsAnAdminstratorOrMember();
  356. }
  357. ( m_wIsAnAdmin == ADMIN) ? isAdmin = true : isAdmin = false;
  358. if ( !isAdmin && !m_dwLogEvents )
  359. {
  360. return;
  361. }
  362. if( isAdmin && !m_dwLogAdmin )
  363. {
  364. return;
  365. }
  366. }
  367. if (!result && bNTLMAuth)
  368. {
  369. DWORD dwSize = strlen(NTLM_LOGON_FAILED) +
  370. strlen(CSession::m_szPeerHostName) +
  371. strlen(CSession::m_szMachineName) + 1;
  372. logStr = new UCHAR[IPC_HEADER_SIZE + dwSize];
  373. if (!logStr)
  374. {
  375. return;
  376. }
  377. SfuZeroMemory(logStr, IPC_HEADER_SIZE + dwSize);
  378. logStr[0] = AUDIT_CLIENT;
  379. memcpy(logStr + 1, &dwSize, sizeof(DWORD)); // No Attack :-), Baskar
  380. _snprintf((LPSTR)(logStr + IPC_HEADER_SIZE), (dwSize - 1), NTLM_LOGON_FAILED, CSession::m_szPeerHostName,
  381. CSession::m_szMachineName);
  382. if (m_dwSysAuditing)
  383. {
  384. ConvertSChartoWChar( ( LPSTR )( logStr+IPC_HEADER_SIZE ), &wideLogStr );
  385. LogEvent(EVENTLOG_AUDIT_FAILURE, 0, wideLogStr);
  386. }
  387. if (m_dwLogToFile)
  388. {
  389. WriteToPipe(CIoHandler::m_hWritePipe, (LPVOID)logStr,
  390. IPC_HEADER_SIZE + dwSize, &(CIoHandler::m_oWriteToPipe));
  391. }
  392. delete[] logStr;
  393. return;
  394. }
  395. DWORD dwRestOfMsgLen = strlen( ADMINISTRATOR ) +
  396. strlen( CSession::m_pszDomain) +
  397. strlen( BLANK ) +
  398. strlen( CSession::m_pszUserName ) +
  399. strlen( BLANK ) +
  400. strlen( FAILED_TO_LOG ) +
  401. strlen( BLANK ) +
  402. strlen( OFF ) +
  403. strlen( BLANK ) +
  404. strlen( FROM ) +
  405. strlen( BLANK ) +
  406. strlen( CSession::m_szPeerHostName ) +
  407. strlen( BLANK ) +
  408. strlen( CSession::m_szMachineName ) + 1 ;
  409. logStr = new UCHAR[ IPC_HEADER_SIZE + dwRestOfMsgLen ];
  410. if( !logStr )
  411. {
  412. return;
  413. }
  414. logStr[0] = AUDIT_CLIENT;
  415. memcpy( logStr+1, &dwRestOfMsgLen, sizeof( DWORD ) ); // No Attack, Baskar :-)
  416. _snprintf( ( LPSTR )( logStr+IPC_HEADER_SIZE ), (dwRestOfMsgLen - 1), "%s%s\\%s %s %s %s %s %s",
  417. isAdmin ? ADMINISTRATOR : "",
  418. CSession::m_pszDomain,
  419. CSession::m_pszUserName,
  420. result ? LOGGED : FAILED_TO_LOG,
  421. logon ? ON : OFF,
  422. FROM,
  423. CSession::m_szPeerHostName,
  424. CSession::m_szMachineName );
  425. if( m_dwSysAuditing )
  426. {
  427. ConvertSChartoWChar( ( LPSTR )( logStr+IPC_HEADER_SIZE ), &wideLogStr );
  428. LogEvent( result ? ( WORD )EVENTLOG_AUDIT_SUCCESS:
  429. ( WORD )EVENTLOG_AUDIT_FAILURE, 0, wideLogStr );
  430. delete[] wideLogStr;
  431. }
  432. if( m_dwLogToFile )
  433. {
  434. WriteToPipe( CIoHandler::m_hWritePipe, ( LPVOID )logStr,
  435. IPC_HEADER_SIZE + dwRestOfMsgLen, &( CIoHandler::m_oWriteToPipe ) );
  436. }
  437. delete[] logStr;
  438. }
  439. #endif
  440. bool
  441. CSession::IsAnAdminstratorOrMember()
  442. {
  443. TOKEN_GROUPS *buffer = NULL;
  444. DWORD needed_length = 0;
  445. BOOL success = FALSE;
  446. ULONG x;
  447. TCHAR szDomain[ MAX_PATH + 1 ];
  448. DWORD dwDomainLen = MAX_PATH + 1;
  449. SID_NAME_USE sidNameUse;
  450. m_wIsAnAdmin = NON_ADMIN;
  451. m_bIsTelnetClientsGroupMember = false;
  452. if (NULL == administrators)
  453. {
  454. SID_IDENTIFIER_AUTHORITY local_system_authority = SECURITY_NT_AUTHORITY;
  455. if (! AllocateAndInitializeSid(
  456. &local_system_authority,
  457. 2, /* there are only two sub-authorities */
  458. SECURITY_BUILTIN_DOMAIN_RID,
  459. DOMAIN_ALIAS_RID_ADMINS,
  460. 0,0,0,0,0,0, /* Don't care about the rest */
  461. &administrators
  462. ))
  463. {
  464. administrators = NULL;
  465. return false;
  466. }
  467. }
  468. if (NULL == pTelnetClientsSid)
  469. {
  470. needed_length = 0;
  471. DWORD dwErr = 0;
  472. LookupAccountName( NULL, TELNETCLIENTS_GROUP_NAME, pTelnetClientsSid, &needed_length,
  473. szDomain, &dwDomainLen, &sidNameUse );
  474. pTelnetClientsSid = ( PSID ) new UCHAR[ needed_length ];
  475. //Even if if allocation fails just go ahead.
  476. success = LookupAccountName( NULL, TELNETCLIENTS_GROUP_NAME, pTelnetClientsSid, &needed_length,
  477. szDomain, &dwDomainLen, &sidNameUse );
  478. if( !success )
  479. {
  480. if (pTelnetClientsSid)
  481. {
  482. delete pTelnetClientsSid;
  483. pTelnetClientsSid = NULL;
  484. }
  485. //return false;
  486. //We should not return back if TelnetClients group does not exist
  487. }
  488. }
  489. /* We are making the first call to GetTokenInformation to get the size of
  490. the memory required for the group data */
  491. _chVERIFY2( success = GetTokenInformation( m_hToken, TokenGroups, buffer,
  492. 0, &needed_length) );
  493. buffer = (TOKEN_GROUPS *)GlobalAlloc(GPTR, needed_length);
  494. if (buffer == NULL)
  495. {
  496. return false;
  497. }
  498. _chVERIFY2( success = GetTokenInformation( m_hToken, TokenGroups, buffer,
  499. needed_length, & needed_length) );
  500. if (! success)
  501. {
  502. _TRACE(TRACE_DEBUGGING,L"GetTokenInformation failed");
  503. GlobalFree(buffer);
  504. return false;
  505. }
  506. _TRACE(TRACE_DEBUGGING,L"GetTokenInformation succeeded Token = 0x%lx", m_hToken);
  507. success = FALSE;
  508. for (x = 0; x < buffer->GroupCount; x ++)
  509. {
  510. if (EqualSid(buffer->Groups[x].Sid, administrators) &&
  511. (buffer->Groups[x].Attributes & SE_GROUP_ENABLED) &&
  512. (!(buffer->Groups[x].Attributes & SE_GROUP_USE_FOR_DENY_ONLY))
  513. )
  514. {
  515. m_bIsTelnetClientsGroupMember = true;
  516. m_wIsAnAdmin = ADMIN;
  517. break;
  518. }
  519. if( pTelnetClientsSid && !m_bIsTelnetClientsGroupMember )
  520. {
  521. if ( EqualSid(buffer->Groups[x].Sid, pTelnetClientsSid ))
  522. {
  523. m_bIsTelnetClientsGroupMember = true;
  524. break;
  525. }
  526. }
  527. }
  528. GlobalFree(buffer);
  529. return ( success ? true : false );
  530. }
  531. void
  532. CSession::Shutdown()
  533. {
  534. #ifdef LOGGING_ENABLED
  535. if( m_fLogonUserResult )
  536. {
  537. LogIfOpted( SUCCESS, LOGOFF );
  538. }
  539. #endif
  540. CScraper::Shutdown();
  541. CIoHandler::Shutdown();
  542. CShell::Shutdown();
  543. _chVERIFY2( DeregisterEventSource( m_hLogHandle ) );
  544. }
  545. bool
  546. CSession::CheckGroupMembership ( bool *fIsAdmin, bool *pfIsTelnetClientsMember)
  547. {
  548. *pfIsTelnetClientsMember = false;
  549. *fIsAdmin = false;
  550. if( m_wIsAnAdmin == DONT_KNOW )
  551. {
  552. IsAnAdminstratorOrMember();
  553. }
  554. if( m_wIsAnAdmin == ADMIN)
  555. {
  556. *fIsAdmin = true;
  557. *pfIsTelnetClientsMember = true; //All admins are default members.
  558. // As defined by US :-)))
  559. }
  560. *pfIsTelnetClientsMember = m_bIsTelnetClientsGroupMember;
  561. return( true );
  562. }