Source code of Windows XP (NT5)
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.

4138 lines
126 KiB

  1. // Copyright (c) 1998-1999 Microsoft Corporation
  2. /*******************************************************************************
  3. *
  4. * utildll.c
  5. *
  6. * UTILDLL multi-user utility support functions
  7. *
  8. *
  9. *******************************************************************************/
  10. /*
  11. * include files
  12. */
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <ntddkbd.h>
  17. #include <ntddmou.h>
  18. #include <ntcsrsrv.h>
  19. #include <ntlsa.h>
  20. #include <ntsam.h>
  21. #include <windows.h>
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <nb30.h>
  25. #include <tapi.h>
  26. #include <raserror.h>
  27. #include <lmerr.h>
  28. #include <lmcons.h>
  29. #include <lmaccess.h>
  30. #include <lmserver.h>
  31. #include <lmwksta.h>
  32. #include <lmremutl.h>
  33. #include <lmapibuf.h>
  34. #define INITGUID
  35. #include "objbase.h"
  36. #include "initguid.h"
  37. //#include "basetyps.h"
  38. #include "devguid.h"
  39. #include "setupapi.h"
  40. #include <winsta.h>
  41. #include <utildll.h>
  42. #include "..\inc\utilsub.h"
  43. #include "..\inc\ansiuni.h"
  44. #include "resource.h"
  45. /*
  46. * Hydrix helpers function internal defines
  47. */
  48. #define INITIAL_ENUMERATION_COUNT 16
  49. #define REGISTRY_NETCARDS TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards")
  50. #define REGISTRY_TITLE TEXT("Title")
  51. #define REGISTRY_SERVICE_NAME TEXT("ServiceName")
  52. #define REGISTRY_HIDDEN TEXT("Hidden")
  53. #define REGISTRY_ROUTE TEXT("Route")
  54. #define REGISTRY_NETBLINKAGE TEXT("SYSTEM\\CurrentControlSet\\Services\\NetBIOS\\Linkage")
  55. #define REGISTRY_NETBLINKAGE_LANAMAP TEXT("LanaMap")
  56. #define REGISTRY_SERVICES TEXT("SYSTEM\\CurrentControlSet\\Services")
  57. #define REGISTRY_DISPLAY_NAME TEXT("DisplayName")
  58. /*
  59. * TAPI defines.
  60. */
  61. #define LOW_MAJOR_VERSION 0x0001
  62. #define LOW_MINOR_VERSION 0x0003
  63. #define HIGH_MAJOR_VERSION 0x0002
  64. #define HIGH_MINOR_VERSION 0x0000
  65. #define LOW_VERSION ((LOW_MAJOR_VERSION << 16) | LOW_MINOR_VERSION)
  66. #define HIGH_VERSION ((HIGH_MAJOR_VERSION << 16) | HIGH_MINOR_VERSION)
  67. /*=============================================================================
  68. == Local Functions Defined
  69. =============================================================================*/
  70. BOOL CheckForComDevice( LPTSTR );
  71. int NetBiosLanaEnum( LANA_ENUM * pLanaEnum );
  72. DWORD EnumerateTapiPorts( PPDPARAMS pPdParams, ULONG Count, ULONG **ppEntries );
  73. VOID CALLBACK DummyTapiCallback(HANDLE, DWORD, DWORD, DWORD, DWORD, DWORD);
  74. BOOL GetAssociatedPortName(char *szKeyName, WCHAR *wszPortName);
  75. BOOL _UserInGroup( LPWSTR pwszUsername, LPWSTR pwszDomain, LPWSTR pwszGroup );
  76. /*******************************************************************************
  77. *
  78. * StandardErrorMessage - Hydrix helper function
  79. *
  80. * Output an error message with optional additional arguments like the
  81. * ErrorMessagexxx routines. Additionally, a standard error line will
  82. * also be output containing the error code and error message associated
  83. * with that code.
  84. *
  85. * ENTRY:
  86. * pszAppName (input)
  87. * Application name for error message box title.
  88. * hwndApp (input)
  89. * Owner window for error message box.
  90. * hinstApp (input)
  91. * Instance handle of application.
  92. * LogonId (input)
  93. * Optional WinStation LogonId for querying special error strings
  94. * from WinStation via WinStationGetInformation API. If this value
  95. * is LOGONID_NONE then no special error message code checking will
  96. * be done.
  97. * nId (input)
  98. * System message code to get standard error string for.
  99. * nErrorResourceID (input)
  100. * Resource ID of the format string to use in the error message.
  101. * ... (input)
  102. * Optional additional arguments to be used with format string.
  103. *
  104. * EXIT:
  105. *
  106. ******************************************************************************/
  107. void WINAPI
  108. StandardErrorMessage( LPCTSTR pszAppName,
  109. HWND hwndApp,
  110. HINSTANCE hinstApp,
  111. ULONG LogonId,
  112. UINT nId,
  113. int nErrorMessageLength,
  114. int nArgumentListLength,
  115. int nErrorResourceID, ...)
  116. {
  117. TCHAR* szClientErrorMessage = NULL;
  118. TCHAR* szClientResourceString = NULL;
  119. TCHAR* szError = NULL;
  120. TCHAR* szFormattedErrorMessage = NULL;
  121. TCHAR* szMessage = NULL;
  122. TCHAR szStandardErrorMessage[STANDARD_ERROR_TEXT_LENGTH + 1];
  123. va_list args;
  124. va_start( args, nErrorResourceID );
  125. szClientErrorMessage = (TCHAR*)malloc((nErrorMessageLength + 1) * sizeof(TCHAR));
  126. if (szClientErrorMessage)
  127. {
  128. LoadString( hinstApp, nErrorResourceID, szClientErrorMessage, nErrorMessageLength );
  129. szClientResourceString = (TCHAR*)malloc((wcslen(szClientErrorMessage) + nArgumentListLength + 1) * sizeof(TCHAR));
  130. if (szClientResourceString != NULL)
  131. {
  132. wvsprintf( szClientResourceString, szClientErrorMessage, args );
  133. LoadString( GetModuleHandle( UTILDLL_NAME ),
  134. IDS_STANDARD_ERROR_FORMAT, szStandardErrorMessage, STANDARD_ERROR_TEXT_LENGTH );
  135. szError = GetSystemMessage( LogonId, nId);
  136. if (szError != NULL)
  137. {
  138. szFormattedErrorMessage = (TCHAR*)malloc((wcslen(szStandardErrorMessage) + 10 + wcslen(szError) + 1) * sizeof(TCHAR));
  139. if (szFormattedErrorMessage != NULL)
  140. {
  141. wsprintf( szFormattedErrorMessage, szStandardErrorMessage, nId, szError);
  142. //lstrcpy(sz1, pszAppName);
  143. szMessage = (TCHAR*)malloc((wcslen(szClientResourceString) + wcslen(szFormattedErrorMessage) + 1) * sizeof(TCHAR));
  144. if (szMessage != NULL)
  145. {
  146. wcscpy(szMessage, szClientResourceString);
  147. wcscat(szMessage, szFormattedErrorMessage);
  148. MessageBox( hwndApp, szMessage, pszAppName, MB_OK | MB_ICONEXCLAMATION );
  149. free(szMessage);
  150. }
  151. free(szFormattedErrorMessage);
  152. }
  153. free (szError);
  154. }
  155. free(szClientResourceString);
  156. }
  157. free (szClientErrorMessage);
  158. }
  159. va_end(args);
  160. } // end StandardErrorMessage
  161. /*******************************************************************************
  162. *
  163. * GetSystemMessageA - Hydrix helper function (ANSI stub)
  164. *
  165. * Return the string associated with the specified system message.
  166. *
  167. * ENTRY:
  168. * (refer to GetSystemMessageW)
  169. * EXIT:
  170. * (refer to GetSystemMessageW)
  171. * If cannot allocate temporary UNICODE buffer to call GetSystemMessageW
  172. * with, the ntents of chBuffer will be set to the "(no error text
  173. * available)" string.
  174. *
  175. ******************************************************************************/
  176. LPSTR WINAPI
  177. GetSystemMessageA( ULONG LogonId,
  178. UINT nId
  179. /*LPSTR chBuffer,
  180. int cbBuffSize*/ )
  181. {
  182. LPWSTR uBuffer = NULL;
  183. LPSTR aBuffer = NULL;
  184. int length;
  185. //Call the GetSystemMessageW function
  186. uBuffer = GetSystemMessageW(LogonId, nId);
  187. if (uBuffer == NULL)
  188. {
  189. //If no message was returned from the GetSystemMessageW
  190. //function just return a generic error message
  191. aBuffer = malloc((NO_ERROR_TEXT_LENGTH + 1) * sizeof(char));
  192. if (aBuffer == NULL)
  193. return NULL;
  194. length = LoadStringA( GetModuleHandle( UTILDLL_NAME ),
  195. IDS_NO_ERROR_TEXT_AVAILABLE,
  196. aBuffer, NO_ERROR_TEXT_LENGTH );
  197. ASSERT(length);
  198. }
  199. else
  200. {
  201. length = wcslen(uBuffer) + 1;
  202. //Convert the result into ANSI in caller supplied buffer.
  203. aBuffer = malloc(length * sizeof(char));
  204. if (aBuffer != NULL)
  205. WideCharToMultiByte(CP_ACP, 0, uBuffer, length - 1, aBuffer, length, 0, 0);
  206. //Free the temporary buffer.
  207. free (uBuffer);
  208. }
  209. //Return message.
  210. return(aBuffer);
  211. } // end GetSystemMessageA
  212. /*******************************************************************************
  213. *
  214. * GetSystemMessageW - Hydrix helper function (UNICODE version)
  215. *
  216. * Return the string associated with the specified system message.
  217. *
  218. * ENTRY:
  219. * LogonId (input)
  220. * Optional WinStation LogonId for querying special error strings
  221. * from WinStation via WinStationGetInformation API. If this value
  222. * is LOGONID_NONE then no special error message code checking will
  223. * be done.
  224. * nId (input)
  225. * System message code to get string for.
  226. * chBuffer (input)
  227. * Points to buffer to fill with system message string.
  228. * cbBuffSize (input)
  229. * Maximum number of characters that can be placed in chBuffer.
  230. *
  231. * EXIT:
  232. * Returns chBuffer. Contents of chBuffer will always be set; to
  233. * the "(no error text available)" string if error.
  234. *
  235. * Note: the total length of chBuffer (including terminating NULL) will
  236. * not exceed the size of the internal temporary buffer (Buffer).
  237. *
  238. ******************************************************************************/
  239. //NA 3/9/01 IMPORTANT: Behavior has changed. Instead of expecting a buffer long
  240. //enough to accomodate the message, it now allocates the memory dynamically, so
  241. //it's up to the calling procedure to deallocate it.
  242. LPWSTR WINAPI
  243. GetSystemMessageW( ULONG LogonId,
  244. UINT nId
  245. /*LPWSTR chBuffer,
  246. int cbBuffSize*/ )
  247. {
  248. LPWSTR chBuffer = NULL;
  249. WCHAR StackBuffer[512];
  250. WCHAR* SpecialBuffer = NULL;
  251. WCHAR* Buffer = NULL;
  252. BOOL bSpecialCitrixError = FALSE;
  253. HINSTANCE cxerror = LoadLibraryW(L"cxerror.dll");
  254. int length = 0;
  255. StackBuffer[0]=0;
  256. //If we have a valid LogonId passed in, determine if the error
  257. //is a special code requiring that the specific error string be
  258. //queried from the WinStation.
  259. if ( LogonId != LOGONID_NONE )
  260. {
  261. switch ( nId )
  262. {
  263. case ERROR_CTX_TD_ERROR:
  264. length = LoadStringW( GetModuleHandle( UTILDLL_NAME ),
  265. IDS_NO_ADDITIONAL_ERROR_INFO,
  266. StackBuffer,
  267. sizeof(StackBuffer)/sizeof(WCHAR) );
  268. ASSERT(length);
  269. SpecialBuffer = malloc((length + 1) * sizeof(WCHAR));
  270. if (SpecialBuffer != NULL)
  271. {
  272. wcscpy(SpecialBuffer, StackBuffer);
  273. bSpecialCitrixError = TRUE;
  274. }
  275. break;
  276. default:
  277. break;
  278. }
  279. }
  280. //See if this is a Citrix error message first...
  281. if ( !cxerror ||
  282. !FormatMessageW( FORMAT_MESSAGE_IGNORE_INSERTS |
  283. FORMAT_MESSAGE_MAX_WIDTH_MASK |
  284. FORMAT_MESSAGE_FROM_HMODULE |
  285. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  286. (LPCVOID)cxerror,
  287. nId,
  288. 0,
  289. (LPWSTR)&Buffer,
  290. 0,
  291. NULL ) )
  292. {
  293. //It's not a Citrix error message; fetch system message.
  294. if ( !FormatMessageW( FORMAT_MESSAGE_IGNORE_INSERTS |
  295. FORMAT_MESSAGE_MAX_WIDTH_MASK |
  296. FORMAT_MESSAGE_FROM_SYSTEM |
  297. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  298. NULL,
  299. nId,
  300. 0,
  301. (LPWSTR)&Buffer,
  302. 0,
  303. NULL ) )
  304. {
  305. //It's not a system message; don't know what the message is...
  306. length = LoadStringW( GetModuleHandle( UTILDLL_NAME ),
  307. IDS_NO_ERROR_TEXT_AVAILABLE,
  308. StackBuffer,
  309. sizeof(StackBuffer)/sizeof(WCHAR) );
  310. ASSERT(length);
  311. Buffer = LocalAlloc(0,(length + 1) * sizeof(WCHAR));
  312. if (Buffer == NULL)
  313. {
  314. if (SpecialBuffer != NULL)
  315. free (SpecialBuffer);
  316. return NULL;
  317. }
  318. wcscpy(Buffer, StackBuffer);
  319. }
  320. }
  321. if ( cxerror )
  322. FreeLibrary(cxerror);
  323. length = wcslen(Buffer);
  324. if ( bSpecialCitrixError )
  325. length += wcslen(SpecialBuffer) + 2;
  326. chBuffer = malloc((length + 1) * sizeof(WCHAR));
  327. if (chBuffer != NULL)
  328. {
  329. wcscpy(chBuffer, Buffer);
  330. //If we fetched a special Citrix error string, tack it onto the end
  331. //of whatever we've buffered already.
  332. if ( bSpecialCitrixError )
  333. {
  334. lstrcatW(chBuffer, L" ");
  335. lstrcatW(chBuffer, SpecialBuffer);
  336. }
  337. }
  338. if (Buffer != NULL)
  339. LocalFree (Buffer);
  340. if (( bSpecialCitrixError ) && (SpecialBuffer != NULL))
  341. free (SpecialBuffer);
  342. return(chBuffer);
  343. } // end GetSystemMessageW
  344. /*******************************************************************************
  345. *
  346. * WinEnumerateDevices - Hydrix helper function
  347. *
  348. * Perform PD device enumeration for the specified PD.
  349. *
  350. * ENTRY:
  351. * hWnd (input)
  352. * Parent window for error message, if needed.
  353. * pPdConfig (input)
  354. * Points to PDCONFIG3 structure of the PD.
  355. * pEntries (output)
  356. * Points to variable to return number of devices that were enumerated.
  357. * bInSetup (input)
  358. * TRUE if we're operating in Setup; FALSE otherwise.
  359. *
  360. * EXIT:
  361. * (PPDPARAMS) Points to the PDPARAMS array containing the enumeration
  362. * results if sucessful. The caller must perform a LocalFree
  363. * of this array when done. NULL if error; error set for
  364. * GetLastError();
  365. * If the returned error code is anything other than
  366. * ERROR_NOT_ENOUGH_MEMORY, the caller can assume that none of the
  367. * requested devices were available to be enumerated.
  368. *
  369. ******************************************************************************/
  370. typedef BOOL (WINAPI * PPDENUMERATE)( PPDCONFIG3, PULONG, PPDPARAMS, PULONG, BOOL );
  371. PPDPARAMS WINAPI
  372. WinEnumerateDevices( HWND hWnd,
  373. PPDCONFIG3 pPdConfig,
  374. PULONG pEntries,
  375. BOOL bInSetup )
  376. {
  377. PPDENUMERATE pPdEnumerate;
  378. ULONG ByteCount;
  379. DWORD Error;
  380. int i;
  381. PPDPARAMS pPdParams = NULL;
  382. /*
  383. * Enumerate according to class.
  384. */
  385. switch ( pPdConfig->Data.SdClass ) {
  386. case SdAsync:
  387. pPdEnumerate = AsyncDeviceEnumerate;
  388. break;
  389. case SdNetwork:
  390. if ( pPdConfig->Data.PdFlag & PD_LANA ) {
  391. /*
  392. * This is a LANA based network PD (ie, NetBIOS). Perform
  393. * NetBIOS enumerate.
  394. */
  395. pPdEnumerate = NetBIOSDeviceEnumerate;
  396. }
  397. else {
  398. /*
  399. * This is a physical lan adapter based network (TCP/IP,
  400. * IPX, SPX, etc). Enumerate based on the associated network
  401. * protocol service name.
  402. */
  403. pPdEnumerate = NetworkDeviceEnumerate;
  404. }
  405. break;
  406. default:
  407. return(NULL);
  408. }
  409. /*
  410. * Call enumerate in loop till we hit enough buffer entries to handle
  411. * a complete enumeration. NOTE: some enumeration routines will return
  412. * the necessary ByteCount on 'insufficient buffer' status; others won't.
  413. */
  414. for ( ByteCount = 0, i = INITIAL_ENUMERATION_COUNT; ; i *= 2 ) {
  415. if ( pPdParams != NULL )
  416. LocalFree(pPdParams);
  417. pPdParams = (PPDPARAMS)LocalAlloc(
  418. LPTR,
  419. ByteCount ?
  420. ByteCount :
  421. (ByteCount = sizeof(PDPARAMS) * i) );
  422. if ( pPdParams == NULL ) {
  423. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  424. goto OutOfMemory;
  425. }
  426. /*
  427. * Perform enumeration and break loop if successful.
  428. */
  429. if ( (*pPdEnumerate)( pPdConfig,
  430. pEntries,
  431. pPdParams,
  432. &ByteCount,
  433. bInSetup ) )
  434. break;
  435. /*
  436. * If we received any other error other than 'insufficient buffer',
  437. * quit (quietly).
  438. */
  439. if ( (Error = GetLastError()) != ERROR_INSUFFICIENT_BUFFER )
  440. goto BadEnumerate;
  441. }
  442. /*
  443. * Success: return the PDPARAMS pointer.
  444. */
  445. return(pPdParams);
  446. /*==============================================================================
  447. * Error returns
  448. *============================================================================*/
  449. BadEnumerate:
  450. LocalFree(pPdParams);
  451. OutOfMemory:
  452. return(NULL);
  453. } // end WinEnumerateDevices
  454. /*******************************************************************************
  455. *
  456. * NetworkDeviceEnumerate - Hydrix helper function
  457. *
  458. * Returns a list of Lan Adapter indexes of network cards bound to the the
  459. * specified protocol. The Lan Adapter is returned in the LanAdapter field
  460. * of each PDPARAMS array. A LanAdapter value of 0 indicates 'any configured
  461. * network card'. Indexes >=1 indicate 1-based index into the specific
  462. * protocol's "servicename"\Linkage\Route registry entry to specify the
  463. * particular network card.
  464. *
  465. * ENTRY:
  466. * pPdConfig (input)
  467. * Points to PDCONFIG3 structure of the PD.
  468. * pEntries (output)
  469. * When the function finishes successfully, the variable pointed to
  470. * by the pEntries parameter contains the number of entries actually
  471. * returned.
  472. * pPdParams (output)
  473. * Points to the buffer to receive the enumeration results, which are
  474. * returned as an array of PDPARAMS structures.
  475. * pByteCount (input/output)
  476. * Points to a variable that specifies the size, in bytes, of the
  477. * pPdParams parameter. If the buffer is too small to receive all the
  478. * entries, on output this variable receives the required size of the
  479. * buffer.
  480. * bInSetup (input)
  481. * TRUE if we're operating in Setup; FALSE otherwise.
  482. *
  483. * EXIT:
  484. * TRUE: enumeration was sucessful; FALSE otherwise.
  485. *
  486. * The error code can be retrieved via GetLastError(), and are the
  487. * following possible values:
  488. * ERROR_INSUFFICIENT_BUFFER
  489. * enumeration failed because of an insufficient pPdParams
  490. * buffer size to contain all devices
  491. * ERROR_DEV_NOT_EXIST
  492. * The specified network's service was not found, indicating that
  493. * the protocol was not configured. This error code can be
  494. * interpreted as 'no devices are configured for the xxx protocol'
  495. * for reporting purposes.
  496. * ERROR_xxxx
  497. * Registry error code.
  498. *
  499. ******************************************************************************/
  500. BOOL WINAPI
  501. NetworkDeviceEnumerate( PPDCONFIG3 pPdConfig,
  502. PULONG pEntries,
  503. PPDPARAMS pPdParams,
  504. PULONG pByteCount,
  505. BOOL bInSetup )
  506. {
  507. ULONG i, Count;
  508. LPTSTR szRoute, szRouteStr;
  509. LONG Status;
  510. DWORD ValueSize, Type;
  511. TCHAR szKey[256];
  512. HKEY Handle;
  513. /*
  514. * Get maximum number of LanAdapter indexes that can be returned.
  515. */
  516. Count = *pByteCount / sizeof(PDPARAMS);
  517. /*
  518. * Form key for service name associated with this PD and fetch
  519. * the Linkage\Route strings.
  520. */
  521. _snwprintf( szKey, sizeof(szKey)/sizeof(TCHAR),
  522. TEXT("%s\\%s\\Linkage"), REGISTRY_SERVICES,
  523. pPdConfig->ServiceName );
  524. if ( (Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, &Handle ))
  525. != ERROR_SUCCESS ) {
  526. Status = ERROR_DEV_NOT_EXIST;
  527. goto BadRegistryOpen;
  528. }
  529. /*
  530. * Alloc and read in the linkage route multi-string.
  531. */
  532. if ( ((Status = RegQueryValueEx( Handle, REGISTRY_ROUTE,
  533. NULL, &Type,
  534. NULL, &ValueSize ))
  535. != ERROR_SUCCESS) || (Type != REG_MULTI_SZ) )
  536. goto BadQuery1;
  537. if ( !(szRoute = (LPTSTR)LocalAlloc(LPTR, ValueSize)) ) {
  538. Status = ERROR_NOT_ENOUGH_MEMORY;
  539. goto BadAlloc;
  540. }
  541. if ( ((Status = RegQueryValueEx( Handle, REGISTRY_ROUTE,
  542. NULL, &Type,
  543. (LPBYTE)szRoute, &ValueSize ))
  544. != ERROR_SUCCESS) )
  545. goto BadQuery2;
  546. /*
  547. * Close the registry key handle and count the route strings to obtain
  548. * the number of entries to report in the enumeration.
  549. */
  550. RegCloseKey(Handle);
  551. for ( i = 1, szRouteStr = szRoute; lstrlen(szRouteStr); i++ )
  552. szRouteStr += (lstrlen(szRouteStr) + 1);
  553. LocalFree(szRoute);
  554. /*
  555. * If we don't have enough PDPARAMS structures to report all of the
  556. * LanAdapter indexes, return error.
  557. */
  558. if ( i > Count ) {
  559. Status = ERROR_INSUFFICIENT_BUFFER;
  560. *pByteCount = (i * sizeof(PDPARAMS));
  561. goto BadBufferSize;
  562. }
  563. /*
  564. * Set the LanAdapter fields of the first 'i' PDPARAMS structures to
  565. * the indexes (0-based), set total number of entries, and return success.
  566. */
  567. for ( Count = 0, *pEntries = i; Count < i; pPdParams++, Count++ )
  568. pPdParams->Network.LanAdapter = (LONG)Count;
  569. return(TRUE);
  570. /*==============================================================================
  571. * Error returns
  572. *============================================================================*/
  573. BadQuery2:
  574. LocalFree(szRoute);
  575. BadAlloc:
  576. BadQuery1:
  577. RegCloseKey(Handle);
  578. BadBufferSize:
  579. BadRegistryOpen:
  580. SetLastError(Status);
  581. return(FALSE);
  582. } // end NetworkDeviceEnumerate
  583. /*******************************************************************************
  584. *
  585. * QueryCurrentWinStation - Hydrix helper function
  586. *
  587. * Query the currently logged-on WinStation information.
  588. *
  589. * ENTRY:
  590. * pWSName (output)
  591. * Points to string to place current WinStation name.
  592. * pUserName (output)
  593. * Points to string to place current User name.
  594. * pLogonId (output)
  595. * Points to ULONG to place current LogonId.
  596. * pFlags (output)
  597. * Points to ULONG to place current WinStation's flags.
  598. *
  599. * EXIT:
  600. * (BOOL) TRUE if the user's current WinStation information was queried
  601. * sucessfully; FALSE otherwise. The error code is set for
  602. * GetLastError() to retrieve.
  603. *
  604. ******************************************************************************/
  605. BOOL WINAPI
  606. QueryCurrentWinStation( PWINSTATIONNAME pWSName,
  607. LPTSTR pUserName,
  608. PULONG pLogonId,
  609. PULONG pFlags )
  610. {
  611. ULONG Flags = 0;
  612. WINSTATIONINFORMATION WSInfo;
  613. #ifdef WINSTA
  614. ULONG ReturnLength;
  615. #endif // WINSTA
  616. #ifdef WINSTA
  617. /*
  618. * Fetch the WinStation's basic information.
  619. */
  620. if ( !WinStationQueryInformation( SERVERNAME_CURRENT,
  621. LOGONID_CURRENT,
  622. WinStationInformation,
  623. &WSInfo,
  624. sizeof(WSInfo),
  625. &ReturnLength ) )
  626. goto BadQuery;
  627. /*
  628. * Check for shadow capability if WinStation is connected. If the
  629. * WinStation is not connected, we can't shadow.
  630. */
  631. if ( WSInfo.ConnectState != State_Disconnected ) {
  632. WDCONFIG WdConfig;
  633. /*
  634. * Query Wd config stuff.
  635. */
  636. if ( !WinStationQueryInformation( SERVERNAME_CURRENT,
  637. LOGONID_CURRENT,
  638. WinStationWd,
  639. &WdConfig,
  640. sizeof(WdConfig),
  641. &ReturnLength ) )
  642. goto BadQuery;
  643. /*
  644. * Set WinStation's Wd flags.
  645. */
  646. Flags = WdConfig.WdFlag;
  647. }
  648. #else
  649. lstrcpy(WSInfo.WinStationName, TEXT("console"));
  650. lstrcpy(WSInfo.UserName, TEXT("bonzo"));
  651. WSInfo.LogonId = 0;
  652. #endif // WINSTA
  653. /*
  654. * Set WinStation information into caller's variables, and return success.
  655. */
  656. lstrcpy( pWSName, WSInfo.WinStationName );
  657. lstrlwr(pWSName);
  658. lstrcpy( pUserName, WSInfo.UserName );
  659. lstrlwr(pUserName);
  660. *pLogonId = WSInfo.LogonId;
  661. *pFlags = Flags;
  662. return(TRUE);
  663. /*==============================================================================
  664. * Error returns
  665. *============================================================================*/
  666. #ifdef WINSTA
  667. BadQuery:
  668. #endif // WINSTA
  669. return(FALSE);
  670. } // end QueryCurrentWinStation
  671. /*******************************************************************************
  672. *
  673. * RegGetNetworkDeviceName - Hydrix helper function
  674. *
  675. * Obtain the network device name associated with the given WinStation PD.
  676. *
  677. * ENTRY:
  678. * hServer (input)
  679. * Handle to Hydrix Server
  680. * pPdConfig (input)
  681. * Points to the PDCONFIG3 structure for the WinStation's PD.
  682. * pPdParams (input)
  683. * Points to the PDPARAMS structure for the WinStation's PD.
  684. * szDeviceName (output)
  685. * Points to buffer to return the network device name.
  686. * nDeviceName (input)
  687. * Specifies the maxmum number of characters that can be stored in
  688. * szDeviceName.
  689. *
  690. * EXIT:
  691. * No return. Will always place a string representation of
  692. * pPdParams->Network.LanAdapter along with an appropriate error string
  693. * in pDeviceName if the network device name could not be read from the
  694. * registry.
  695. *
  696. ******************************************************************************/
  697. typedef struct _LANAMAP {
  698. BYTE enabled;
  699. BYTE lana;
  700. } LANAMAP, *PLANAMAP;
  701. LONG WINAPI
  702. RegGetNetworkDeviceName( HANDLE hServer,
  703. PPDCONFIG3 pPdConfig,
  704. PPDPARAMS pPdParams,
  705. LPTSTR szDeviceName,
  706. int nDeviceName )
  707. {
  708. int i, length;
  709. LPTSTR szRoute, szRouteStr, p;
  710. LONG Status = ERROR_SUCCESS;
  711. DWORD ValueSize, Type;
  712. TCHAR szKey[256];
  713. HKEY Handle;
  714. HKEY hkey_local_machine;
  715. PLANAMAP pLanaMap, pLana;
  716. if ( hServer == NULL)
  717. hkey_local_machine = HKEY_LOCAL_MACHINE;
  718. else
  719. hkey_local_machine = hServer;
  720. /*
  721. * Check for NetBIOS (PD_LANA) mapping or other mapping.
  722. */
  723. if ( !(pPdConfig->Data.PdFlag & PD_LANA) ) {
  724. LPTSTR szRoute, szRouteStr;
  725. /*
  726. * Non-LANA mapping. If the LanAdapter is 0, treat this as the
  727. * special 'all configured network cards' value and return that
  728. * string as the device name.
  729. */
  730. if ( pPdParams->Network.LanAdapter == 0 ) {
  731. TCHAR szString[256];
  732. length = LoadString( GetModuleHandle( UTILDLL_NAME ),
  733. IDS_ALL_LAN_ADAPTERS, szString, 256 );
  734. ASSERT(length);
  735. lstrncpy(szDeviceName, szString, nDeviceName);
  736. szDeviceName[nDeviceName-1] = TEXT('\0');
  737. return Status;
  738. }
  739. /*
  740. * Form key for service name associated with this PD and fetch
  741. * the Linkage\Route strings.
  742. */
  743. _snwprintf( szKey, sizeof(szKey)/sizeof(TCHAR),
  744. TEXT("%s\\%s\\Linkage"), REGISTRY_SERVICES,
  745. pPdConfig->ServiceName );
  746. if ( (Status = RegOpenKeyEx( hkey_local_machine, szKey, 0,
  747. KEY_READ, &Handle ))
  748. != ERROR_SUCCESS )
  749. goto Error;
  750. /*
  751. * Alloc and read in the linkage route multi-string.
  752. */
  753. if ( ((Status = RegQueryValueEx( Handle, REGISTRY_ROUTE,
  754. NULL, &Type,
  755. NULL, &ValueSize ))
  756. != ERROR_SUCCESS) || (Type != REG_MULTI_SZ) )
  757. goto Error;
  758. if ( !(szRoute = (LPTSTR)LocalAlloc(LPTR, ValueSize)) ) {
  759. Status = ERROR_NOT_ENOUGH_MEMORY;
  760. goto Error;
  761. }
  762. if ( ((Status = RegQueryValueEx( Handle, REGISTRY_ROUTE,
  763. NULL, &Type,
  764. (LPBYTE)szRoute, &ValueSize ))
  765. != ERROR_SUCCESS) ) {
  766. LocalFree(szRoute);
  767. goto Error;
  768. }
  769. /*
  770. * Close the registry key handle and point to the route string
  771. * associated with this LanAdapter index.
  772. */
  773. RegCloseKey(Handle);
  774. for ( i = 1, szRouteStr = szRoute;
  775. i < pPdParams->Network.LanAdapter; i++ ) {
  776. szRouteStr += (lstrlen(szRouteStr) + 1);
  777. if ( !lstrlen(szRouteStr) ) {
  778. /*
  779. * Error: Index past end of route multi-string.
  780. */
  781. LocalFree(szRoute);
  782. Status = ERROR_DEV_NOT_EXIST;
  783. goto Error;
  784. }
  785. }
  786. /*
  787. * Isolate the service string representing the lowest binding
  788. * in the route and convert it to its display name.
  789. */
  790. *(p = (szRouteStr + lstrlen(szRouteStr) - 1)) = TEXT('\0');
  791. for ( ; *p != TEXT('\"'); p-- );
  792. p++;
  793. if ( (Status = RegGetNetworkServiceName( hServer, p, szDeviceName, nDeviceName ))
  794. != ERROR_SUCCESS ) {
  795. LocalFree(szRoute);
  796. goto Error;
  797. }
  798. /*
  799. * Clean up and return.
  800. */
  801. LocalFree(szRoute);
  802. return Status;
  803. }
  804. else {
  805. /*
  806. * NetBIOS LANA #: see which LanaMap entry corresponds to the specified
  807. * Lan Adapter.
  808. */
  809. if ( (Status = RegOpenKeyEx( hkey_local_machine, REGISTRY_NETBLINKAGE, 0,
  810. KEY_READ, &Handle ))
  811. != ERROR_SUCCESS )
  812. goto Error;
  813. /*
  814. * Alloc and read the LanaMap
  815. */
  816. if ( ((Status = RegQueryValueEx( Handle, REGISTRY_NETBLINKAGE_LANAMAP,
  817. NULL, &Type,
  818. NULL, &ValueSize))
  819. != ERROR_SUCCESS) || (Type != REG_BINARY) ) {
  820. RegCloseKey(Handle);
  821. goto Error;
  822. }
  823. if ( !(pLanaMap = (PLANAMAP)LocalAlloc(LPTR, ValueSize)) ) {
  824. Status = ERROR_NOT_ENOUGH_MEMORY;
  825. goto Error;
  826. }
  827. if ( (Status = RegQueryValueEx( Handle, REGISTRY_NETBLINKAGE_LANAMAP,
  828. NULL, &Type,
  829. (LPBYTE)pLanaMap, &ValueSize))
  830. != ERROR_SUCCESS ) {
  831. LocalFree(pLanaMap);
  832. RegCloseKey(Handle);
  833. goto Error;
  834. }
  835. /*
  836. * Loop through LanaMap to check for match with the specified Lan
  837. * Adapter #.
  838. */
  839. for ( pLana = pLanaMap, i = 0;
  840. i < (int)(ValueSize / sizeof(LANAMAP));
  841. i++, pLana++ ) {
  842. if ( pLana->lana == (BYTE)(pPdParams->Network.LanAdapter) ) {
  843. TCHAR szHighestBinding[256], szLowestBinding[256];
  844. LocalFree(pLanaMap);
  845. /*
  846. * Match found. Alloc and fetch the Route multi-string
  847. */
  848. if ( ((Status = RegQueryValueEx( Handle,
  849. REGISTRY_ROUTE,
  850. NULL, &Type,
  851. NULL, &ValueSize))
  852. != ERROR_SUCCESS) || (Type != REG_MULTI_SZ) ) {
  853. RegCloseKey(Handle);
  854. goto Error;
  855. }
  856. if ( !(szRoute = (LPTSTR)LocalAlloc(LPTR, ValueSize)) ) {
  857. Status = ERROR_NOT_ENOUGH_MEMORY;
  858. goto Error;
  859. }
  860. if ( (Status = RegQueryValueEx( Handle,
  861. REGISTRY_ROUTE,
  862. NULL, &Type,
  863. (LPBYTE)szRoute, &ValueSize))
  864. != ERROR_SUCCESS ) {
  865. LocalFree(szRoute);
  866. RegCloseKey(Handle);
  867. goto Error;
  868. }
  869. /*
  870. * Free the registry key handle and make a local copy of the
  871. * 'i'th multi string, which is the binding route for this lana.
  872. */
  873. RegCloseKey(Handle);
  874. for ( szRouteStr = szRoute; i > 0; i-- )
  875. szRouteStr += (lstrlen(szRouteStr) + 1);
  876. lstrncpy(szDeviceName, szRouteStr, nDeviceName);
  877. szDeviceName[nDeviceName-1] = TEXT('\0');
  878. LocalFree(szRoute);
  879. /*
  880. * Isolate the service string representing the highest binding
  881. * in the route and convert it to its display name.
  882. */
  883. szRouteStr = szDeviceName + 1; // skip first "
  884. for ( p = szRouteStr; *p && *p != TEXT('\"'); p++ );
  885. if ( !(*p) )
  886. goto Error;
  887. *p = TEXT('\0');
  888. if ( (Status = RegGetNetworkServiceName(
  889. hServer,
  890. szRouteStr,
  891. szHighestBinding,
  892. sizeof(szHighestBinding)/sizeof(TCHAR) ))
  893. != ERROR_SUCCESS )
  894. goto Error;
  895. /*
  896. * Isolate the service string representing the lowest binding
  897. * in the route and convert it to its display name.
  898. */
  899. if ( !(*(szRouteStr = p+1)) ) {
  900. *szLowestBinding = TEXT('\0');
  901. }
  902. else {
  903. *(p = (szRouteStr + lstrlen(szRouteStr) - 1)) = TEXT('\0');
  904. for ( ; *p != TEXT('\"'); p-- );
  905. p++;
  906. if ( (Status = RegGetNetworkServiceName(
  907. hServer,
  908. p,
  909. szLowestBinding,
  910. sizeof(szLowestBinding)/sizeof(TCHAR) ))
  911. != ERROR_SUCCESS )
  912. goto Error;
  913. }
  914. /*
  915. * Build the complete name string.
  916. */
  917. _snwprintf( szDeviceName, nDeviceName, TEXT("%s => %s"),
  918. szHighestBinding, szLowestBinding );
  919. /*
  920. * Return.
  921. */
  922. return ERROR_SUCCESS;
  923. }
  924. }
  925. /*
  926. * No match found.
  927. */
  928. LocalFree(pLanaMap);
  929. RegCloseKey(Handle);
  930. goto Error;
  931. }
  932. /*==============================================================================
  933. * Error returns
  934. *============================================================================*/
  935. Error:
  936. {
  937. TCHAR sz1[256], sz2[1024];
  938. int length;
  939. length = LoadString( GetModuleHandle( UTILDLL_NAME ),
  940. (pPdConfig->Data.PdFlag & PD_LANA) ?
  941. IDP_ERROR_REGLANA :
  942. IDP_ERROR_REGNETCARD,
  943. sz1, 256 );
  944. wsprintf( sz2, sz1, pPdParams->Network.LanAdapter, Status );
  945. lstrncpy(szDeviceName, sz2, nDeviceName);
  946. szDeviceName[nDeviceName-1] = TEXT('\0');
  947. }
  948. return Status;
  949. } // end RegGetNetworkDeviceName
  950. /*******************************************************************************
  951. *
  952. * RegGetNetworkServiceName - Hydrix helper function
  953. *
  954. * Obtain the display name associated with a given network service name.
  955. * If the service is a reference to a physical network card, will return
  956. * the title of the card as obtained from the LOCAL_MACHINE\Software\
  957. * Microsoft\Windows NT\NetworkCards registry.
  958. *
  959. * ENTRY:
  960. * hServer (input)
  961. * Handle of the Hydrix Server
  962. * szServiceKey (input)
  963. * Key string into the LOCAL_MACHINE\System\CurrentControlSet\Services
  964. * registry.
  965. * szServiceName (output)
  966. * Points to buffer to return the service's display name.
  967. * nServiceName (input)
  968. * Specifies the maxmum number of characters that can be stored in
  969. * szServiceName.
  970. *
  971. * EXIT:
  972. * ERROR_SUCCESS if a service name was sucessfully found and returned;
  973. * error code otherwise.
  974. *
  975. * NOTE: If the service name is for an entry in the NetworkCards resistry
  976. * and the entry is flagged as 'hidden', the service name will be
  977. * blank. This will flag caller's logic to ignore the entry.
  978. *
  979. ******************************************************************************/
  980. LONG WINAPI
  981. RegGetNetworkServiceName( HANDLE hServer,
  982. LPTSTR szServiceKey,
  983. LPTSTR szServiceName,
  984. int nServiceName )
  985. {
  986. LONG Status;
  987. DWORD ValueSize, Type, dwValue;
  988. TCHAR szKey[256];
  989. LPTSTR szTemp;
  990. HKEY Handle;
  991. HKEY hkey_local_machine;
  992. if (hServer == NULL)
  993. hkey_local_machine = HKEY_LOCAL_MACHINE;
  994. else
  995. hkey_local_machine = hServer;
  996. lstrnprintf( szKey, sizeof(szKey)/sizeof(TCHAR),
  997. TEXT("%s\\%s"), REGISTRY_SERVICES, szServiceKey );
  998. if ( (Status = RegOpenKeyEx( hkey_local_machine,
  999. szKey, 0,
  1000. KEY_READ, &Handle ))
  1001. != ERROR_SUCCESS )
  1002. return(Status);
  1003. /*
  1004. * Alloc and read in the service's DisplayName value (if there).
  1005. */
  1006. if ( ((Status = RegQueryValueEx( Handle, REGISTRY_DISPLAY_NAME,
  1007. NULL, &Type,
  1008. NULL, &ValueSize ))
  1009. != ERROR_SUCCESS) || (Type != REG_SZ) ) {
  1010. HKEY Subkey;
  1011. FILETIME KeyTime;
  1012. DWORD i;
  1013. /*
  1014. * The service doesn't have a DisplayName associated with it (it's a
  1015. * Network Card's service name). Traverse the NetworkCards registry
  1016. * entries and find the entry associated with this service name
  1017. * (if it exists).
  1018. */
  1019. RegCloseKey(Handle);
  1020. if ( (Status = RegOpenKeyEx( hkey_local_machine,
  1021. REGISTRY_NETCARDS, 0,
  1022. KEY_READ, &Handle ))
  1023. != ERROR_SUCCESS )
  1024. return(Status);
  1025. for ( i = 0, ValueSize = sizeof(szKey)/sizeof(TCHAR) ;
  1026. RegEnumKeyEx( Handle, i, szKey, &ValueSize,
  1027. NULL, NULL, NULL, &KeyTime ) == ERROR_SUCCESS ;
  1028. i++, ValueSize = sizeof(szKey)/sizeof(TCHAR) ) {
  1029. /*
  1030. * Open the Network Card's registry.
  1031. */
  1032. if ( (Status = RegOpenKeyEx( Handle,
  1033. szKey, 0,
  1034. KEY_READ, &Subkey ))
  1035. != ERROR_SUCCESS ) {
  1036. RegCloseKey(Handle);
  1037. return(Status);
  1038. }
  1039. /*
  1040. * Alloc and fetch the card's service name. Continue net card
  1041. * enumeration if service name not found.
  1042. */
  1043. if ( ((Status = RegQueryValueEx( Subkey,
  1044. REGISTRY_SERVICE_NAME,
  1045. NULL, &Type,
  1046. NULL, &ValueSize))
  1047. != ERROR_SUCCESS) || (Type != REG_SZ) ) {
  1048. RegCloseKey(Subkey);
  1049. continue;
  1050. }
  1051. szTemp = (LPTSTR)LocalAlloc(LPTR, ValueSize);
  1052. if(NULL == szTemp)
  1053. {
  1054. RegCloseKey(Subkey);
  1055. RegCloseKey(Handle);
  1056. return ERROR_NOT_ENOUGH_MEMORY;
  1057. }
  1058. if ( (Status = RegQueryValueEx( Subkey,
  1059. REGISTRY_SERVICE_NAME,
  1060. NULL, &Type,
  1061. (LPBYTE)szTemp, &ValueSize))
  1062. != ERROR_SUCCESS ) {
  1063. LocalFree(szTemp);
  1064. RegCloseKey(Subkey);
  1065. continue;
  1066. }
  1067. /*
  1068. * If the current Network Card's service name matches the service
  1069. * name that we're looking for, fetch the card's title.
  1070. */
  1071. if ( !lstrcmpi(szServiceKey, szTemp) ) {
  1072. LocalFree(szTemp);
  1073. ValueSize = sizeof(dwValue);
  1074. if ( (RegQueryValueEx( Subkey, REGISTRY_HIDDEN,
  1075. NULL, &Type,
  1076. (LPBYTE)&dwValue, &ValueSize )
  1077. == ERROR_SUCCESS) &&
  1078. (Type == REG_DWORD) &&
  1079. (dwValue == 1) ) {
  1080. /*
  1081. * Entry is hidden: return empty title.
  1082. */
  1083. *szServiceName = TEXT('\0');
  1084. }
  1085. else {
  1086. /*
  1087. * Entry is not hidden: Alloc for the card's title.
  1088. */
  1089. if ( ((Status = RegQueryValueEx( Subkey,
  1090. REGISTRY_TITLE,
  1091. NULL, &Type,
  1092. NULL, &ValueSize))
  1093. != ERROR_SUCCESS) || (Type != REG_SZ) ) {
  1094. RegCloseKey(Subkey);
  1095. RegCloseKey(Handle);
  1096. return(Status);
  1097. }
  1098. szTemp = (LPTSTR)LocalAlloc(LPTR, ValueSize);
  1099. if(NULL == szTemp)
  1100. {
  1101. RegCloseKey(Subkey);
  1102. RegCloseKey(Handle);
  1103. return ERROR_NOT_ENOUGH_MEMORY;
  1104. }
  1105. /*
  1106. * Fetch the title.
  1107. */
  1108. if ( (Status = RegQueryValueEx( Subkey,
  1109. REGISTRY_TITLE,
  1110. NULL, &Type,
  1111. (LPBYTE)szTemp, &ValueSize))
  1112. != ERROR_SUCCESS ) {
  1113. LocalFree(szTemp);
  1114. RegCloseKey(Subkey);
  1115. RegCloseKey(Handle);
  1116. return(Status);
  1117. }
  1118. /*
  1119. * Copy the card's title.
  1120. */
  1121. lstrncpy(szServiceName, szTemp, nServiceName);
  1122. szServiceName[nServiceName-1] = TEXT('\0');
  1123. LocalFree(szTemp);
  1124. }
  1125. /*
  1126. * Clean up and return success.
  1127. */
  1128. RegCloseKey(Subkey);
  1129. RegCloseKey(Handle);
  1130. return(ERROR_SUCCESS);
  1131. }
  1132. else {
  1133. /*
  1134. * This is not the Network Card that we're looking for. Close
  1135. * it's registry key, free the service name buffer, and continue
  1136. * enumeration loop.
  1137. */
  1138. LocalFree(szTemp);
  1139. RegCloseKey(Subkey);
  1140. }
  1141. }
  1142. /*
  1143. * Network Card not found with service name matching the one supplied.
  1144. * Close NetworkCards registry key and return failure,
  1145. */
  1146. RegCloseKey(Handle);
  1147. return(ERROR_DEV_NOT_EXIST);
  1148. }
  1149. else {
  1150. szTemp = (LPTSTR)LocalAlloc(LPTR, ValueSize);
  1151. if(NULL == szTemp)
  1152. {
  1153. RegCloseKey(Handle);
  1154. return ERROR_NOT_ENOUGH_MEMORY;
  1155. }
  1156. if ( ((Status = RegQueryValueEx( Handle, REGISTRY_DISPLAY_NAME,
  1157. NULL, &Type,
  1158. (LPBYTE)szTemp, &ValueSize ))
  1159. == ERROR_SUCCESS) )
  1160. lstrncpy(szServiceName, szTemp, nServiceName);
  1161. szServiceName[nServiceName-1] = TEXT('\0');
  1162. LocalFree(szTemp);
  1163. RegCloseKey(Handle);
  1164. return(Status);
  1165. }
  1166. } // end RegGetNetworkServiceName
  1167. /*******************************************************************************
  1168. *
  1169. * AsyncDeviceEnumerate - Hydrix helper function
  1170. *
  1171. * Returns a list of async device names. This will return both 'COM' devices
  1172. * and TAPI configured modems.
  1173. *
  1174. * ENTRY:
  1175. * pPdConfig (input)
  1176. * Points to PDCONFIG3 structure of the PD.
  1177. * pEntries (output)
  1178. * When the function finishes successfully, the variable pointed to
  1179. * by the pEntries parameter contains the number of entries actually
  1180. * returned.
  1181. * pPdParams (output)
  1182. * Points to the buffer to receive the enumeration results, which are
  1183. * returned as an array of PDPARAMS structures.
  1184. * pByteCount (input/output)
  1185. * Points to a variable that specifies the size, in bytes, of the
  1186. * pPdParams parameter. If the buffer is too small to receive all the
  1187. * entries, on output this variable is set to 0 (caller should double
  1188. * the input buffer and try again).
  1189. * bInSetup (input)
  1190. * TRUE if we're operating in Setup; FALSE otherwise.
  1191. * EXIT:
  1192. * TRUE: enumeration was sucessful; FALSE otherwise.
  1193. *
  1194. * The error code can be retrieved via GetLastError(), and are the
  1195. * following possible values:
  1196. * ERROR_NOT_ENOUGH_MEMORY
  1197. * not enough memory to allocate working buffer(s)
  1198. * ERROR_INSUFFICIENT_BUFFER
  1199. * enumeration failed because of an insufficient pPdParams
  1200. * buffer size to contain all devices
  1201. * ERROR_DEV_NOT_EXIST
  1202. * the QueryDosDevice call failed. This error code can be
  1203. * interpreted as 'no async devices are configured' for reporting
  1204. * purposes.
  1205. *
  1206. ******************************************************************************/
  1207. #define MAX_QUERY_BUFFER (1024*16)
  1208. BOOL WINAPI
  1209. AsyncDeviceEnumerate( PPDCONFIG3 pPdConfig,
  1210. PULONG pEntries,
  1211. PPDPARAMS pPdParams,
  1212. PULONG pByteCount,
  1213. BOOL bInSetup )
  1214. {
  1215. DWORD Error = ERROR_SUCCESS;
  1216. ULONG Count;
  1217. HKEY hRoot = NULL;
  1218. DWORD BufSize, NameSize, Type, Index, SaveBufSize, SaveNameSize;
  1219. LONG Result = 0;
  1220. LONG nDosDevice = 0;
  1221. LPTSTR pBuffer = NULL, pBufferEnd = NULL;
  1222. LPTSTR pNameBuffer = NULL, pName;
  1223. BOOLEAN bRetVal = FALSE;
  1224. /*
  1225. * Get maximum number of names that can be returned
  1226. */
  1227. Count = *pByteCount / sizeof(PDPARAMS);
  1228. *pByteCount = 0;
  1229. *pEntries = 0;
  1230. /*
  1231. * Allocate buffer
  1232. */
  1233. SaveBufSize = MAX_QUERY_BUFFER;
  1234. SaveNameSize = MAX_QUERY_BUFFER;
  1235. BufSize = SaveBufSize;
  1236. NameSize = SaveNameSize;
  1237. if ( !(pBuffer = (LPTSTR)LocalAlloc(LPTR, BufSize * sizeof(TCHAR))) ) {
  1238. Error = ERROR_NOT_ENOUGH_MEMORY;
  1239. goto Cleanup;
  1240. }
  1241. if ( !(pNameBuffer = (LPTSTR)LocalAlloc(LPTR, NameSize)) ) {
  1242. Error = ERROR_NOT_ENOUGH_MEMORY;
  1243. goto Cleanup;
  1244. }
  1245. /*
  1246. * If we're in Setup, obtain devices from the SERIALCOMM section in
  1247. * LOCAL MACHINE registry, since the serial device driver(s) are most
  1248. * likely not running. Otherwise, we'll query all DosDevices and
  1249. * return those that are COM devices and are not currently in use.
  1250. */
  1251. if ( bInSetup ) {
  1252. Result = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1253. TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
  1254. 0, // Reserved
  1255. KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,
  1256. &hRoot );
  1257. if ( Result != ERROR_SUCCESS ) {
  1258. //
  1259. // This is usually the result of having no ports, so the key
  1260. // SERIALCOMM does not exist.
  1261. //
  1262. goto Cleanup;
  1263. }
  1264. for ( Index=0; ; Index++ ) {
  1265. // Each enumerate stomps on our buffer sizes
  1266. BufSize = SaveBufSize;
  1267. NameSize = SaveNameSize;
  1268. Result = RegEnumValue( hRoot,
  1269. Index,
  1270. pBuffer,
  1271. &BufSize,
  1272. NULL, // Reserved
  1273. &Type,
  1274. (LPBYTE)pNameBuffer,
  1275. &NameSize );
  1276. if ( Result == ERROR_INSUFFICIENT_BUFFER ) {
  1277. // Reallocate the buffer
  1278. LocalFree( pBuffer );
  1279. pBuffer = (LPTSTR)LocalAlloc(LPTR, BufSize * sizeof(TCHAR));
  1280. if ( pBuffer == NULL ) {
  1281. // Try and reallocate next key
  1282. SaveBufSize = BufSize = 0;
  1283. continue;
  1284. }
  1285. else {
  1286. SaveBufSize = BufSize;
  1287. }
  1288. // Reallocate the name buffer
  1289. LocalFree( pNameBuffer );
  1290. pNameBuffer = (LPTSTR)LocalAlloc(LPTR, NameSize);
  1291. if ( pNameBuffer == NULL ) {
  1292. // Try and reallocate next key
  1293. SaveNameSize = NameSize = 0;
  1294. continue;
  1295. }
  1296. else {
  1297. SaveNameSize = NameSize;
  1298. }
  1299. Result = RegEnumValue( hRoot,
  1300. Index,
  1301. pBuffer,
  1302. &BufSize,
  1303. NULL, // Reserved
  1304. &Type,
  1305. (LPBYTE)pNameBuffer,
  1306. &NameSize );
  1307. }
  1308. // We are done
  1309. if ( Result == ERROR_NO_MORE_ITEMS ) {
  1310. bRetVal = TRUE;
  1311. Result = 0;
  1312. goto Cleanup;
  1313. }
  1314. if ( Result != ERROR_SUCCESS ) {
  1315. goto Cleanup;
  1316. }
  1317. if ( Count > 0 ) {
  1318. if ( Type != REG_SZ ) {
  1319. continue;
  1320. }
  1321. pPdParams->SdClass = SdAsync;
  1322. lstrcpy( pPdParams->Async.DeviceName, pNameBuffer );
  1323. pPdParams++;
  1324. Count--;
  1325. (*pEntries)++;
  1326. }
  1327. else {
  1328. Error = ERROR_INSUFFICIENT_BUFFER;
  1329. goto Cleanup;
  1330. }
  1331. }
  1332. }
  1333. else { // not in Setup
  1334. /*
  1335. * Get complete device list
  1336. */
  1337. nDosDevice = QueryDosDevice( NULL, pBuffer, MAX_QUERY_BUFFER );
  1338. if ( !nDosDevice)
  1339. {
  1340. Error = ERROR_DEV_NOT_EXIST;
  1341. goto Cleanup;
  1342. }
  1343. /*
  1344. * Find each device name in list
  1345. */
  1346. pName = pBuffer;
  1347. pBufferEnd = pBuffer + nDosDevice;
  1348. while ( *pName && (pName < pBufferEnd) ) {
  1349. if ( CheckForComDevice( pName ) ) {
  1350. if ( Count > 0 ) {
  1351. pPdParams->SdClass = SdAsync;
  1352. lstrcpy( pPdParams->Async.DeviceName, pName );
  1353. pPdParams++;
  1354. Count--;
  1355. (*pEntries)++;
  1356. }
  1357. else {
  1358. Error = ERROR_INSUFFICIENT_BUFFER;
  1359. goto Cleanup;
  1360. }
  1361. }
  1362. pName += (lstrlen(pName) + 1);
  1363. }
  1364. bRetVal = TRUE; // sucessful enumeration
  1365. }
  1366. Cleanup:
  1367. /*
  1368. * If no errors yet, perform TAPI device enumeration.
  1369. */
  1370. if ( bRetVal ) {
  1371. if ( (Error = EnumerateTapiPorts( pPdParams,
  1372. Count,
  1373. &pEntries ))
  1374. != ERROR_SUCCESS ) {
  1375. bRetVal = FALSE;
  1376. }
  1377. }
  1378. if ( pBuffer ) {
  1379. LocalFree( pBuffer );
  1380. }
  1381. if ( pNameBuffer ) {
  1382. LocalFree( pNameBuffer );
  1383. }
  1384. if ( hRoot ) {
  1385. CloseHandle( hRoot );
  1386. }
  1387. SetLastError(Error);
  1388. return(bRetVal);
  1389. } // AsyncDeviceEnumerate
  1390. /*******************************************************************************
  1391. *
  1392. * NetBIOSDeviceEnumerate - Hydrix helper function
  1393. *
  1394. * Returns a list of NetBIOS lana adapter numbers.
  1395. *
  1396. * ENTRY:
  1397. * pPdConfig (input)
  1398. * Points to PDCONFIG3 structure of the PD.
  1399. * pEntries (output)
  1400. * When the function finishes successfully, the variable pointed to
  1401. * by the pEntries parameter contains the number of entries actually
  1402. * returned.
  1403. * pPdParams (output)
  1404. * Points to the buffer to receive the enumeration results, which are
  1405. * returned as an array of PDPARAMS structures.
  1406. * pByteCount (input/output)
  1407. * Points to a variable that specifies the size, in bytes, of the
  1408. * pPdParams parameter. If the buffer is too small to receive all the
  1409. * entries, on output this variable receives the required size of the
  1410. * buffer.
  1411. * bInSetup (input)
  1412. * TRUE if we're operating in Setup; FALSE otherwise.
  1413. *
  1414. * EXIT:
  1415. * TRUE: enumeration was sucessful; FALSE otherwise.
  1416. *
  1417. * The error code can be retrieved via GetLastError(), and are the
  1418. * following possible values:
  1419. * v ERROR_INSUFFICIENT_BUFFER
  1420. * enumeration failed because of an insufficient pPdParams
  1421. * buffer size to contain all devices
  1422. * ERROR_DEV_NOT_EXIST
  1423. * the NetBiosLanaEnum call failed. This error code can be
  1424. * interpreted as 'no netbios devices are configured' for reporting
  1425. * purposes.
  1426. *
  1427. ******************************************************************************/
  1428. BOOL WINAPI
  1429. NetBIOSDeviceEnumerate( PPDCONFIG3 pPdConfig,
  1430. PULONG pEntries,
  1431. PPDPARAMS pPdParams,
  1432. PULONG pByteCount,
  1433. BOOL bInSetup )
  1434. {
  1435. LANA_ENUM LanaEnum;
  1436. NTSTATUS Status;
  1437. int i;
  1438. /*
  1439. * Issue netbios enum command
  1440. */
  1441. if ( Status = NetBiosLanaEnum( &LanaEnum ) ) {
  1442. SetLastError(ERROR_DEV_NOT_EXIST);
  1443. return(FALSE);
  1444. }
  1445. /*
  1446. * Make sure user's buffer is big enough
  1447. */
  1448. if ( LanaEnum.length > (*pByteCount / sizeof(PDPARAMS)) ) {
  1449. *pByteCount = LanaEnum.length * sizeof(PDPARAMS);
  1450. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1451. return(FALSE);
  1452. }
  1453. /*
  1454. * Return number of entries
  1455. */
  1456. *pEntries = (ULONG) LanaEnum.length;
  1457. /*
  1458. * Return lana numbers
  1459. */
  1460. for ( i=0; i < (int)LanaEnum.length; i++, pPdParams++ ) {
  1461. pPdParams->SdClass = SdNetwork;
  1462. pPdParams->Network.LanAdapter = LanaEnum.lana[i];
  1463. }
  1464. return(TRUE);
  1465. } // NetBIOSDeviceEnumerate
  1466. /*******************************************************************************
  1467. *
  1468. * FormDecoratedAsyncDeviceName - Hydrix helper function
  1469. *
  1470. * Format a decorated async device name if a modem is defined.
  1471. *
  1472. * ENTRY:
  1473. * pDeviceName (output)
  1474. * Points to buffer that will contain the decorated name (or undecorated
  1475. * name if no modem).
  1476. * pPdParams (input)
  1477. * Points to the ASYNCCONFIG structure to be used in forming the
  1478. * decorated name.
  1479. *
  1480. * EXIT:
  1481. *
  1482. ******************************************************************************/
  1483. void WINAPI
  1484. FormDecoratedAsyncDeviceName( LPTSTR pDeviceName,
  1485. PASYNCCONFIG pAsyncConfig )
  1486. {
  1487. if ( *(pAsyncConfig->ModemName) )
  1488. wsprintf( pDeviceName, TEXT("%s - %s"),
  1489. pAsyncConfig->DeviceName,
  1490. pAsyncConfig->ModemName );
  1491. else
  1492. lstrcpy( pDeviceName,
  1493. pAsyncConfig->DeviceName );
  1494. } // end FormDecoratedAsyncDeviceName
  1495. /*******************************************************************************
  1496. *
  1497. * ParseDecoratedAsyncDeviceName - Hydrix helper function
  1498. *
  1499. * Given a decorated async device name, form it's component device and
  1500. * modem name portions.
  1501. *
  1502. * ENTRY:
  1503. * pDeviceName (input)
  1504. * Points to buffer that contain the decorated async device name.
  1505. * pAsyncConfig (output)
  1506. * Points to the ASYNCCONFIG structure to save the device (in
  1507. * ->DeviceName) and modem (in ->ModemName).
  1508. * EXIT:
  1509. *
  1510. ******************************************************************************/
  1511. void WINAPI
  1512. ParseDecoratedAsyncDeviceName( LPCTSTR pDeviceName,
  1513. PASYNCCONFIG pAsyncConfig )
  1514. {
  1515. int i;
  1516. /*
  1517. * Form DeviceName portion up to the first blank.
  1518. */
  1519. for ( i=0; *pDeviceName && (*pDeviceName != TEXT(' ')); i++ )
  1520. (pAsyncConfig->DeviceName)[i] = *pDeviceName++;
  1521. (pAsyncConfig->DeviceName)[i] = TEXT('\0');
  1522. /*
  1523. * Skip the ' - ' decoration (to the next space).
  1524. */
  1525. if ( *pDeviceName ) {
  1526. for ( pDeviceName++;
  1527. *pDeviceName && (*pDeviceName != TEXT(' '));
  1528. pDeviceName++ );
  1529. }
  1530. /*
  1531. * Form the ModemName from the remainder of the string.
  1532. */
  1533. i = 0;
  1534. if ( *pDeviceName ) {
  1535. for ( pDeviceName++; *pDeviceName ; i++ )
  1536. (pAsyncConfig->ModemName)[i] = *pDeviceName++;
  1537. }
  1538. (pAsyncConfig->ModemName)[i] = TEXT('\0');
  1539. } // end ParseDecoratedAsyncDeviceName
  1540. /*******************************************************************************
  1541. *
  1542. * SetupAsyncCdConfig - Hydrix helper function
  1543. *
  1544. * Given a properly configured ASYNCCONFIG structure, set up a given
  1545. * CDCONFIG structure.
  1546. *
  1547. * ENTRY:
  1548. * pAsyncConfig (input)
  1549. * Points properly configured ASYNCCONFIG structure.
  1550. * pCdConfig (output)
  1551. * Points to the CDCONFIG structure to setup.
  1552. * EXIT:
  1553. *
  1554. ******************************************************************************/
  1555. void WINAPI
  1556. SetupAsyncCdConfig( PASYNCCONFIG pAsyncConfig,
  1557. PCDCONFIG pCdConfig )
  1558. {
  1559. memset(pCdConfig, 0, sizeof(CDCONFIG));
  1560. if ( *(pAsyncConfig->ModemName) ) {
  1561. pCdConfig->CdClass = CdModem;
  1562. lstrcpy( pCdConfig->CdName, TEXT("cdmodem") );
  1563. lstrcpy( pCdConfig->CdDLL, TEXT("cdmodem.dll") );
  1564. }
  1565. } // end SetupAsyncCdConfig
  1566. /*******************************************************************************
  1567. *
  1568. * InstallModem - Hydrix helper function
  1569. *
  1570. * Install UNIMODEM modem(s).
  1571. *
  1572. * ENTRY:
  1573. * hwndOwner
  1574. * Window handle that owns the installation dialog.
  1575. * EXIT:
  1576. * TRUE: installation completed; FALSE: error or user canceled.
  1577. *
  1578. * If an error, the error code can be retrieved via GetLastError().
  1579. *
  1580. ******************************************************************************/
  1581. BOOL WINAPI
  1582. InstallModem( HWND hwndOwner )
  1583. {
  1584. HDEVINFO hdi;
  1585. BOOL bStatus = FALSE;
  1586. HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1587. /*
  1588. * Create a modem DeviceInfoSet
  1589. */
  1590. if ( (hdi = SetupDiCreateDeviceInfoList( (LPGUID)&GUID_DEVCLASS_MODEM,
  1591. hwndOwner )) ) {
  1592. SP_INSTALLWIZARD_DATA iwd;
  1593. /*
  1594. * Initialize the InstallWizardData
  1595. */
  1596. memset(&iwd, 0, sizeof(iwd));
  1597. iwd.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  1598. iwd.ClassInstallHeader.InstallFunction = DIF_INSTALLWIZARD;
  1599. iwd.hwndWizardDlg = hwndOwner;
  1600. /*
  1601. * Set the InstallWizardData as the ClassInstallParams
  1602. */
  1603. if ( SetupDiSetClassInstallParams( hdi,
  1604. NULL,
  1605. (PSP_CLASSINSTALL_HEADER)&iwd,
  1606. sizeof(iwd)) ) {
  1607. /*
  1608. * Call the class installer to invoke the installation
  1609. * wizard.
  1610. */
  1611. SetCursor(hcur);
  1612. hcur = NULL;
  1613. if ( SetupDiCallClassInstaller( DIF_INSTALLWIZARD,
  1614. hdi,
  1615. NULL) ) {
  1616. /*
  1617. * Success. The wizard was invoked and finished.
  1618. */
  1619. SetupDiCallClassInstaller( DIF_DESTROYWIZARDDATA,
  1620. hdi,
  1621. NULL );
  1622. bStatus = TRUE;
  1623. }
  1624. }
  1625. /*
  1626. * Clean up
  1627. */
  1628. SetupDiDestroyDeviceInfoList( hdi );
  1629. }
  1630. if (hcur)
  1631. SetCursor(hcur);
  1632. return(bStatus);
  1633. } // end InstallModem
  1634. /*******************************************************************************
  1635. *
  1636. * ConfigureModem - Hydrix helper function
  1637. *
  1638. * Configure the specified UNIMODEM modem.
  1639. *
  1640. * ENTRY:
  1641. * pModemName
  1642. * Name of UNIMODEM modem to configure.
  1643. * hwndOwner
  1644. * Window handle that owns the configuration dialog.
  1645. * EXIT:
  1646. * TRUE: configuration was sucessful; FALSE otherwise.
  1647. *
  1648. * The error code can be retrieved via GetLastError().
  1649. *
  1650. ******************************************************************************/
  1651. BOOL WINAPI
  1652. ConfigureModem( LPCTSTR pModemName,
  1653. HWND hwndOwner )
  1654. {
  1655. BOOL bStatus = FALSE;
  1656. COMMCONFIG ccDummy;
  1657. COMMCONFIG * pcc;
  1658. DWORD dwSize;
  1659. HCURSOR hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1660. ccDummy.dwProviderSubType = PST_MODEM;
  1661. dwSize = sizeof(COMMCONFIG);
  1662. GetDefaultCommConfig(pModemName, &ccDummy, &dwSize);
  1663. pcc = (COMMCONFIG *)LocalAlloc(LPTR, (UINT)dwSize);
  1664. if ( pcc ) {
  1665. pcc->dwProviderSubType = PST_MODEM;
  1666. if ( GetDefaultCommConfig(pModemName, pcc, &dwSize) ) {
  1667. COMMCONFIG *pccOld = (COMMCONFIG *)LocalAlloc(LPTR, (UINT)dwSize);
  1668. if ( pccOld ) {
  1669. memcpy(pccOld, pcc, dwSize);
  1670. }
  1671. SetCursor(hcur);
  1672. hcur = NULL;
  1673. bStatus = TRUE;
  1674. if ( CommConfigDialog(pModemName, hwndOwner, pcc) ) {
  1675. if ( !SetDefaultCommConfig(pModemName, pcc, dwSize) )
  1676. bStatus = FALSE;
  1677. }
  1678. LocalFree((HLOCAL)pcc);
  1679. }
  1680. }
  1681. else
  1682. {
  1683. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1684. }
  1685. if (hcur)
  1686. SetCursor(hcur);
  1687. return(bStatus);
  1688. } // end ConfigureModem
  1689. ///////////////////////////////////////////////////////////////////////////////
  1690. // Static Helper Functions
  1691. /***************************************************************************
  1692. *
  1693. * InitServerLock
  1694. *
  1695. * Since we do not require the user to call an initialize function,
  1696. * we must initialize our critical section in a thread safe manner.
  1697. *
  1698. * The problem is, a critical section is needed to guard against multiple
  1699. * threads trying to init the critical section at the same time.
  1700. *
  1701. * The solution that Nt uses, in which RtlInitializeCriticalSection itself
  1702. * uses, is to wait on a kernel supported process wide Mutant before proceding.
  1703. * This Mutant almost works by itself, but RtlInitializeCriticalSection does
  1704. * not wait on it until after trashing the semaphore count. So we wait on
  1705. * it ourselves, since it can be acquired recursively.
  1706. *
  1707. ***************************************************************************/
  1708. typedef struct SERVERVERSION {
  1709. struct SERVERVERSION * pNext;
  1710. char ServerNameA[MAX_BR_NAME+1];
  1711. USHORT ServerVersion;
  1712. } SERVERVERSION, *PSERVERVERSION;
  1713. BOOLEAN G_fLockInited = FALSE;
  1714. PSERVERVERSION G_pServerList = NULL;
  1715. RTL_CRITICAL_SECTION G_ServerLock;
  1716. NTSTATUS
  1717. InitServerLock()
  1718. {
  1719. NTSTATUS status = STATUS_SUCCESS;
  1720. RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1721. /*
  1722. * Make sure another thread did not beat us here
  1723. */
  1724. if ( !G_fLockInited ) {
  1725. status = RtlInitializeCriticalSection( &G_ServerLock );
  1726. if (status == STATUS_SUCCESS) {
  1727. G_fLockInited = TRUE;
  1728. }
  1729. }
  1730. RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
  1731. return status;
  1732. }
  1733. /*******************************************************************************
  1734. *
  1735. * CheckForComDevice - local helper function
  1736. *
  1737. * check if device name is a serial com device
  1738. *
  1739. * ENTRY:
  1740. * pName (input)
  1741. * device name
  1742. *
  1743. * EXIT:
  1744. * TRUE - serial device
  1745. * FALSE - not a serial device
  1746. *
  1747. ******************************************************************************/
  1748. static BOOL
  1749. CheckForComDevice( LPTSTR pName )
  1750. {
  1751. FILE_FS_DEVICE_INFORMATION DeviceInformation;
  1752. IO_STATUS_BLOCK IoStatus;
  1753. HANDLE Handle;
  1754. DEVICENAME Name;
  1755. NTSTATUS Status;
  1756. if ( (lstrlen(pName) == 2 && pName[1] == TEXT(':')) ||
  1757. !lstrcmpi(pName, TEXT("aux")) ||
  1758. !lstrnicmp(pName, TEXT("lpt"), 3) ||
  1759. !lstrnicmp(pName, TEXT("prn"), 3) ||
  1760. !lstrnicmp(pName, TEXT("display"), 7) ||
  1761. !lstrnicmp(pName, TEXT("$VDMLPT"), 7))
  1762. return(FALSE);
  1763. lstrcpy( Name, TEXT("\\\\.\\") );
  1764. lstrcat( Name, pName );
  1765. try
  1766. {
  1767. Handle = CreateFile( Name,
  1768. GENERIC_READ | GENERIC_WRITE,
  1769. 0, // exclusive access
  1770. NULL, // no security attr
  1771. OPEN_EXISTING, // must exist
  1772. 0,
  1773. NULL // no template
  1774. );
  1775. }
  1776. __except (1)
  1777. {
  1778. if ( Handle != INVALID_HANDLE_VALUE )
  1779. {
  1780. CloseHandle( Handle );
  1781. Handle = INVALID_HANDLE_VALUE;
  1782. }
  1783. }
  1784. if ( Handle == INVALID_HANDLE_VALUE )
  1785. return(FALSE);
  1786. Status = NtQueryVolumeInformationFile( (HANDLE) Handle,
  1787. &IoStatus,
  1788. &DeviceInformation,
  1789. sizeof(DeviceInformation),
  1790. FileFsDeviceInformation );
  1791. CloseHandle( Handle );
  1792. if ( (Status != STATUS_SUCCESS) ||
  1793. (DeviceInformation.DeviceType != FILE_DEVICE_SERIAL_PORT) )
  1794. return(FALSE);
  1795. return(TRUE);
  1796. } // end CheckForComDevice
  1797. /*******************************************************************************
  1798. *
  1799. * NetBiosLanaEnum - local helper function
  1800. *
  1801. * enumerate lana numbers
  1802. *
  1803. * ENTRY:
  1804. * pLanaEnum (input)
  1805. * pointer to receive LAN_ENUM structure
  1806. * EXIT:
  1807. * NO_ERROR - succesful
  1808. *
  1809. ******************************************************************************/
  1810. typedef struct _LANA_MAP {
  1811. BOOLEAN Enum;
  1812. UCHAR Lana;
  1813. } LANA_MAP, *PLANA_MAP;
  1814. static int
  1815. NetBiosLanaEnum( LANA_ENUM * pLanaEnum )
  1816. {
  1817. int ProviderCount;
  1818. void * pProviderNames = NULL;
  1819. PLANA_MAP pLanaMap = NULL;
  1820. HKEY netbiosKey = NULL;
  1821. ULONG providerListLength;
  1822. ULONG lanaMapLength;
  1823. ULONG type;
  1824. int i;
  1825. LPTSTR currentProviderName;
  1826. int rc;
  1827. //
  1828. // Read the registry for information on all Netbios providers,
  1829. // including Lana numbers, protocol numbers, and provider device
  1830. // names. First, open the Netbios key in the registry.
  1831. //
  1832. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGISTRY_NETBLINKAGE, 0,
  1833. MAXIMUM_ALLOWED, &netbiosKey );
  1834. if ( rc != NO_ERROR ) {
  1835. goto error_exit;
  1836. }
  1837. //
  1838. // Determine the size of the provider names. We need this so
  1839. // that we can allocate enough memory to hold it.
  1840. //
  1841. providerListLength = 0;
  1842. rc = RegQueryValueEx(
  1843. netbiosKey,
  1844. TEXT("Bind"),
  1845. NULL,
  1846. &type,
  1847. NULL,
  1848. &providerListLength
  1849. );
  1850. if ( rc != ERROR_MORE_DATA && rc != NO_ERROR ) {
  1851. goto error_exit;
  1852. }
  1853. //
  1854. // Allocate enough memory to hold the mapping.
  1855. //
  1856. if ( (pProviderNames = LocalAlloc(LPTR,providerListLength)) == NULL ) {
  1857. rc = ERROR_NOT_ENOUGH_MEMORY;
  1858. goto error_exit;
  1859. }
  1860. //
  1861. // Get the list of transports from the registry.
  1862. //
  1863. rc = RegQueryValueEx(
  1864. netbiosKey,
  1865. TEXT("Bind"),
  1866. NULL,
  1867. &type,
  1868. (PVOID)pProviderNames,
  1869. &providerListLength
  1870. );
  1871. if ( rc != NO_ERROR ) {
  1872. goto error_exit;
  1873. }
  1874. //
  1875. // Determine the size of the Lana map. We need this so that we
  1876. // can allocate enough memory to hold it.
  1877. //
  1878. providerListLength = 0;
  1879. rc = RegQueryValueEx(
  1880. netbiosKey,
  1881. TEXT("LanaMap"),
  1882. NULL,
  1883. &type,
  1884. NULL,
  1885. &lanaMapLength
  1886. );
  1887. if ( rc != ERROR_MORE_DATA && rc != NO_ERROR ) {
  1888. goto error_exit;
  1889. }
  1890. //
  1891. // Allocate enough memory to hold the Lana map.
  1892. //
  1893. if ( (pLanaMap = LocalAlloc(LPTR,lanaMapLength)) == NULL ) {
  1894. rc = ERROR_NOT_ENOUGH_MEMORY;
  1895. goto error_exit;
  1896. }
  1897. //
  1898. // Get the list of transports from the registry.
  1899. //
  1900. rc = RegQueryValueEx(
  1901. netbiosKey,
  1902. TEXT("LanaMap"),
  1903. NULL,
  1904. &type,
  1905. (PVOID)pLanaMap,
  1906. &lanaMapLength
  1907. );
  1908. if ( rc != NO_ERROR ) {
  1909. goto error_exit;
  1910. }
  1911. //
  1912. // Determine the number of Netbios providers loaded on the system.
  1913. //
  1914. ProviderCount = (int) (lanaMapLength / sizeof(LANA_MAP));
  1915. //
  1916. // Fill in the lana array
  1917. //
  1918. pLanaEnum->length = 0;
  1919. for ( currentProviderName = pProviderNames, i = 0;
  1920. *currentProviderName != UNICODE_NULL && i < ProviderCount;
  1921. currentProviderName += lstrlen( currentProviderName ) + 1, i++ ) {
  1922. if ( pLanaMap[i].Enum &&
  1923. lstrstr( currentProviderName, TEXT("Nbf_") ) ) {
  1924. pLanaEnum->lana[ pLanaEnum->length++ ] = pLanaMap[i].Lana;
  1925. }
  1926. }
  1927. error_exit:
  1928. if ( netbiosKey != NULL )
  1929. RegCloseKey( netbiosKey );
  1930. if ( pProviderNames != NULL )
  1931. LocalFree( pProviderNames );
  1932. if ( pLanaMap != NULL )
  1933. LocalFree( pLanaMap );
  1934. return( rc );
  1935. }
  1936. //
  1937. // NOTE: Butchd 9-26-96
  1938. // all of this following TAPI-related code is from various
  1939. // \nt\private\net\ras\src\ui\setup\src\ files
  1940. //
  1941. /******************************************************************************
  1942. *
  1943. * EnumerateTapiPorts - local helper function
  1944. *
  1945. * Determine all TAPI configured modems.
  1946. *
  1947. * ENTRY
  1948. * pPdParams (output)
  1949. * Points to array of PDPARAMS structures to save enumerated TAPI
  1950. * modems into.
  1951. * Count (input)
  1952. * Specifies number of entries in the pPdParams array.
  1953. * ppEntries (input/output)
  1954. * Points to pointer to variable containing the existing number of
  1955. * PDPARAMS entries already stored at addresses prior to pPdParams.
  1956. * The referenced variable will be incremented by the number of
  1957. * TAPI modems found and stored in the pPdParams array.
  1958. * EXIT
  1959. * Returns ERROR_SUCCESS if successful, error code if not.
  1960. *
  1961. *****************************************************************************/
  1962. DWORD
  1963. EnumerateTapiPorts( PPDPARAMS pPdParams,
  1964. ULONG Count,
  1965. ULONG **ppEntries )
  1966. {
  1967. LINEINITIALIZEEXPARAMS params;
  1968. LINEDEVCAPS *linedevcaps ;
  1969. LINEEXTENSIONID extensionid ;
  1970. HLINEAPP TapiLine = (HLINEAPP)0;
  1971. DWORD NegotiatedApiVersion ;
  1972. DWORD NegotiatedExtVersion = 0;
  1973. WORD i;
  1974. DWORD lines = 0 ;
  1975. BYTE buffer[1000] ;
  1976. CHAR szregkey[512];
  1977. WCHAR wszDeviceName[DEVICENAME_LENGTH+1];
  1978. WCHAR wszModemName[DEVICENAME_LENGTH+1];
  1979. CHAR szModemName[DEVICENAME_LENGTH+1];
  1980. LONG lerr;
  1981. DWORD Status = ERROR_TAPI_CONFIGURATION;
  1982. DWORD dwApiVersion = HIGH_VERSION;
  1983. BOOL fSuccess = FALSE;
  1984. ULONG RASIsUsingPort = 0;
  1985. HKEY CurKey, CurKey2;
  1986. DWORD KeyCount=0, KeySize, CurSize, DataType;
  1987. TCHAR szSubKey[255], CurRASDev[1024], szMainKey[255], *pCurRASDev;
  1988. /*
  1989. * Un-comment / edit the following line if time needed to allow newly
  1990. * added modem to appear in TAPI's enumeration list.
  1991. */
  1992. // Sleep(4000L);
  1993. /*
  1994. * Initialize TAPI.
  1995. */
  1996. memset(&params, 0, sizeof(params));
  1997. params.dwTotalSize = sizeof(params);
  1998. params.dwOptions = LINEINITIALIZEEXOPTION_USEEVENT;
  1999. if ( lerr = lineInitializeExA( &TapiLine,
  2000. GetModuleHandle( UTILDLL_NAME ),
  2001. (LINECALLBACK)DummyTapiCallback,
  2002. NULL,
  2003. &lines,
  2004. &dwApiVersion,
  2005. &params ) )
  2006. goto error;
  2007. /*
  2008. * Get configured TAPI modems on all lines.
  2009. */
  2010. for ( i = 0; i < lines; i++ ) {
  2011. if ( lineNegotiateAPIVersion( TapiLine, i,
  2012. LOW_VERSION, HIGH_VERSION,
  2013. &NegotiatedApiVersion,
  2014. &extensionid ) ) {
  2015. continue ;
  2016. }
  2017. memset( buffer, 0, sizeof(buffer) );
  2018. linedevcaps = (LINEDEVCAPS *)buffer;
  2019. linedevcaps->dwTotalSize = sizeof(buffer);
  2020. /*
  2021. * Get this line's dev caps (ANSI).
  2022. */
  2023. if ( lineGetDevCapsA( TapiLine, i,
  2024. NegotiatedApiVersion,
  2025. NegotiatedExtVersion,
  2026. linedevcaps ) ) {
  2027. continue ;
  2028. }
  2029. /*
  2030. li * Only process modems.
  2031. */
  2032. if ( linedevcaps->dwMediaModes & LINEMEDIAMODE_DATAMODEM ) {
  2033. /*
  2034. * The linedevcaps stuff is in ASCII.
  2035. */
  2036. DWORD j;
  2037. char *temp;
  2038. /*
  2039. * Convert all nulls in the device class string to non nulls.
  2040. */
  2041. for ( j = 0, temp = (char *)((BYTE *)linedevcaps+linedevcaps->dwDeviceClassesOffset);
  2042. j < linedevcaps->dwDeviceClassesSize;
  2043. j++, temp++ ) {
  2044. if ( *temp == '\0' )
  2045. *temp = ' ';
  2046. }
  2047. /*
  2048. * Select only those devices that have comm/datamodem as a
  2049. * device class.
  2050. */
  2051. if ( strstr( (char*)((BYTE *)linedevcaps+linedevcaps->dwDeviceClassesOffset),
  2052. "comm/datamodem" ) == NULL ) {
  2053. continue;
  2054. }
  2055. /*
  2056. * Fetch modem name (line name).
  2057. */
  2058. strncpy( szModemName,
  2059. (char *)((BYTE *)linedevcaps+linedevcaps->dwLineNameOffset),
  2060. DEVICENAME_LENGTH );
  2061. szModemName[DEVICENAME_LENGTH] = '\0';
  2062. MultiByteToWideChar(CP_ACP, 0, szModemName, -1, wszModemName, DEVICENAME_LENGTH + 1);
  2063. /*
  2064. * The registry key name where the modem specific information is
  2065. * stored is at dwDevSpecificOffset + 2 * DWORDS
  2066. *
  2067. * The device specifc string is not unicode so copy that as
  2068. * an ansii string
  2069. */
  2070. strncpy( szregkey,
  2071. (char *)linedevcaps+linedevcaps->dwDevSpecificOffset+(2*sizeof(DWORD)),
  2072. linedevcaps->dwDevSpecificSize );
  2073. szregkey[linedevcaps->dwDevSpecificSize] = '\0';
  2074. if ( !GetAssociatedPortName( szregkey, wszDeviceName ) ) {
  2075. goto error;
  2076. }
  2077. /*
  2078. * If RAS is installed and is using the port configured with this
  2079. * modem, we will return the modem, but the Parity field will be
  2080. * set to 1, indicating that RAS is using the port. This is done
  2081. * so that WinCfg (or other caller) can filter out the raw port
  2082. * (device name) as well as the TAPI modem from the list.
  2083. */
  2084. RASIsUsingPort = 0;
  2085. //See if the RAS Key even exists
  2086. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\RAS\\TAPI DEVICES"), 0, KEY_ALL_ACCESS, &CurKey) == ERROR_SUCCESS) {
  2087. KeySize = sizeof(szSubKey) / sizeof( TCHAR );
  2088. KeyCount = 0;
  2089. while (RegEnumKeyEx( CurKey,
  2090. KeyCount++,
  2091. szSubKey,
  2092. &KeySize,
  2093. NULL,
  2094. NULL,
  2095. NULL,
  2096. NULL
  2097. ) != ERROR_NO_MORE_ITEMS) {
  2098. wcscpy(szMainKey,TEXT("SOFTWARE\\Microsoft\\RAS\\TAPI DEVICES"));
  2099. wcscat(szMainKey,TEXT("\\"));
  2100. wcscat(szMainKey,szSubKey);
  2101. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, szMainKey, 0, KEY_ALL_ACCESS, &CurKey2) == ERROR_SUCCESS) {
  2102. CurSize = sizeof(CurRASDev);
  2103. if (RegQueryValueEx(
  2104. CurKey2,
  2105. TEXT("Address"),
  2106. NULL,
  2107. &DataType,
  2108. (LPBYTE)CurRASDev,
  2109. &CurSize
  2110. ) == ERROR_SUCCESS) {
  2111. for ( pCurRASDev = CurRASDev;
  2112. *pCurRASDev && !RASIsUsingPort; ) {
  2113. if ( lstrcmpi(pCurRASDev, wszDeviceName) == 0 )
  2114. RASIsUsingPort = 1;
  2115. else
  2116. pCurRASDev += (wcslen(pCurRASDev) + 1);
  2117. }
  2118. }
  2119. RegCloseKey(CurKey2);
  2120. }
  2121. KeySize = sizeof(szSubKey) / sizeof( TCHAR );
  2122. }
  2123. RegCloseKey(CurKey);
  2124. }
  2125. /*
  2126. * Save DeviceName and ModemName to PDPARAMS
  2127. * structure and bump counts. Also, set the BaudRate
  2128. * element to the TAPI line index so that the caller can
  2129. * determine the most recently added line, and set the Parity
  2130. * field to 0 if RAS is not using the line, 1 if RAS is
  2131. * using the line (so caller can filter properly).
  2132. */
  2133. if ( Count > 0 ) {
  2134. pPdParams->SdClass = SdAsync;
  2135. lstrcpy( pPdParams->Async.DeviceName, wszDeviceName );
  2136. lstrcpy( pPdParams->Async.ModemName, wszModemName );
  2137. pPdParams->Async.BaudRate = (ULONG)i;
  2138. pPdParams->Async.Parity = RASIsUsingPort;
  2139. pPdParams++;
  2140. Count--;
  2141. (**ppEntries)++;
  2142. }
  2143. else {
  2144. Status = ERROR_INSUFFICIENT_BUFFER;
  2145. goto error;
  2146. }
  2147. }
  2148. }
  2149. Status = ERROR_SUCCESS;
  2150. error:
  2151. if ( TapiLine )
  2152. lineShutdown(TapiLine);
  2153. return( Status );
  2154. } // end EnumerateTapiPorts
  2155. /******************************************************************************
  2156. *
  2157. * DummyTapiCallback - local helper function
  2158. *
  2159. * A dummy callback routine to satisfy TAPI initialization.
  2160. *
  2161. * ENTRY
  2162. * (see TAPI lineInitialize documentation)
  2163. * EXIT
  2164. *
  2165. *****************************************************************************/
  2166. VOID CALLBACK
  2167. DummyTapiCallback (HANDLE context, DWORD msg, DWORD instance, DWORD param1, DWORD param2, DWORD param3)
  2168. {
  2169. } // end DummyTapiCallback
  2170. /******************************************************************************
  2171. *
  2172. * GetAssociatedPortName - local helper function
  2173. *
  2174. * Determine the 'attached to' (port) for the given modem via it's device
  2175. * specific registry key (szKeyName).
  2176. *
  2177. * ENTRY
  2178. * (see TAPI lineInitialize documentation)
  2179. * EXIT
  2180. *
  2181. *****************************************************************************/
  2182. #define VALNAME_ATTACHEDTO "AttachedTo"
  2183. BOOL
  2184. GetAssociatedPortName( char *szKeyName,
  2185. WCHAR * wszPortName )
  2186. {
  2187. HKEY hKeyModem;
  2188. DWORD dwType;
  2189. DWORD cbValueBuf;
  2190. char szPortName[DEVICENAME_LENGTH+1];
  2191. if ( RegOpenKeyExA( HKEY_LOCAL_MACHINE,
  2192. szKeyName,
  2193. 0,
  2194. KEY_READ,
  2195. &hKeyModem ) ) {
  2196. return( FALSE );
  2197. }
  2198. cbValueBuf = sizeof( szPortName );
  2199. if ( RegQueryValueExA( hKeyModem,
  2200. VALNAME_ATTACHEDTO,
  2201. NULL,
  2202. &dwType,
  2203. (LPBYTE)&szPortName,
  2204. &cbValueBuf ) ) {
  2205. return ( FALSE );
  2206. }
  2207. RegCloseKey( hKeyModem );
  2208. MultiByteToWideChar(CP_ACP, 0, szPortName, -1, wszPortName, DEVICENAME_LENGTH + 1);
  2209. return( TRUE );
  2210. } // end GetAssociatedPortName
  2211. /*
  2212. * Defines and typedefs
  2213. */
  2214. typedef struct _userlist {
  2215. struct _userlist *pNext;
  2216. WCHAR UserName[USERNAME_LENGTH+1];
  2217. } USERLIST, *PUSERLIST;
  2218. #define MAX_DOMAINANDNAME ((DOMAIN_LENGTH+1+USERNAME_LENGTH+1)*sizeof(WCHAR))
  2219. #define MAX_BUFFER (10*MAX_DOMAINANDNAME)
  2220. /*
  2221. * Local variables
  2222. */
  2223. WCHAR *s_pszCompareList = NULL;
  2224. WCHAR s_szServer[256];
  2225. /*
  2226. * Local functions.
  2227. */
  2228. WCHAR *_ctxCreateAnonymousUserCompareList();
  2229. /*******************************************************************************
  2230. *
  2231. * InitializeAnonymousUserCompareList - helper routine
  2232. *
  2233. * Creates a list of all local users who currently belong to the local
  2234. * Anonymous group on the specified server, and saves the server name.
  2235. *
  2236. * ENTRY:
  2237. * pszServer (input)
  2238. * Name of server to query users for.
  2239. *
  2240. ******************************************************************************/
  2241. void WINAPI
  2242. InitializeAnonymousUserCompareList( const WCHAR *pszServer )
  2243. {
  2244. if ( s_pszCompareList )
  2245. free( s_pszCompareList );
  2246. wcscpy(s_szServer, pszServer);
  2247. s_pszCompareList = _ctxCreateAnonymousUserCompareList();
  2248. }
  2249. /*******************************************************************************
  2250. *
  2251. * HaveAnonymousUsersChanged - helper routine
  2252. *
  2253. * Using the saved server name, fetch current list of local users that
  2254. * belong to the local Anonymous group and compare with saved list.
  2255. *
  2256. * ENTRY:
  2257. * EXIT:
  2258. * On exit, the original compare list is freed and server name cleared.
  2259. *
  2260. ******************************************************************************/
  2261. BOOL WINAPI
  2262. HaveAnonymousUsersChanged()
  2263. {
  2264. BOOL bChanged = FALSE;
  2265. WCHAR *pszNewCompareList, *pszOldName, *pszNewName;
  2266. if ( s_pszCompareList && *s_szServer ) {
  2267. if ( pszNewCompareList = _ctxCreateAnonymousUserCompareList() ) {
  2268. bChanged = TRUE;
  2269. for ( pszOldName = s_pszCompareList, pszNewName = pszNewCompareList;
  2270. (*pszOldName != L'\0') && (*pszNewName != L'\0'); ) {
  2271. if ( wcscmp(pszOldName, pszNewName) )
  2272. break;
  2273. pszOldName += (wcslen(pszOldName) + 1);
  2274. pszNewName += (wcslen(pszNewName) + 1);
  2275. }
  2276. if ( (*pszOldName == L'\0') && (*pszNewName == L'\0') )
  2277. bChanged = FALSE;
  2278. free(pszNewCompareList);
  2279. }
  2280. }
  2281. if ( s_pszCompareList )
  2282. free( s_pszCompareList );
  2283. s_pszCompareList = NULL;
  2284. memset(s_szServer, 0, sizeof(s_szServer));
  2285. return(bChanged);
  2286. }
  2287. /*******************************************************************************
  2288. *
  2289. * _ctxCreateAnonymousUserCompareList - local routine
  2290. *
  2291. * Routine to get local anonymous users and place in sorted string list.
  2292. *
  2293. * ENTRY:
  2294. * EXIT:
  2295. * pszCompareList - Returns pointer to buffer containing sorted string
  2296. * list of local anonymous users, double null terminated.
  2297. * NULL if error.
  2298. *
  2299. ******************************************************************************/
  2300. WCHAR *
  2301. _ctxCreateAnonymousUserCompareList()
  2302. {
  2303. DWORD EntriesRead, EntriesLeft, ResumeHandle = 0;
  2304. NET_API_STATUS rc;
  2305. WCHAR DomainAndUsername[256], *pszCompareList = NULL;
  2306. DWORD i, TotalCharacters = 0;
  2307. LPWSTR p;
  2308. PLOCALGROUP_MEMBERS_INFO_3 plgrmi3 = NULL;
  2309. PUSERLIST pUserListBase = NULL, pNewUser;
  2310. /*
  2311. * Loop till all local anonymous users have been retrieved.
  2312. */
  2313. do {
  2314. /*
  2315. * Get first batch
  2316. */
  2317. if ( (rc = NetLocalGroupGetMembers( s_szServer,
  2318. PSZ_ANONYMOUS,
  2319. 3,
  2320. (LPBYTE *)&plgrmi3,
  2321. MAX_BUFFER,
  2322. &EntriesRead,
  2323. &EntriesLeft,
  2324. (PDWORD_PTR)(&ResumeHandle) )) &&
  2325. (rc != ERROR_MORE_DATA ) ) {
  2326. break;
  2327. }
  2328. /*
  2329. * Process first batch
  2330. */
  2331. for ( i = 0; i < EntriesRead; i++ ) {
  2332. /*
  2333. * Get DOMAIN/USERNAME
  2334. */
  2335. wcscpy( DomainAndUsername, plgrmi3[i].lgrmi3_domainandname );
  2336. /*
  2337. * Check that DOMAIN is actually LOCAL MACHINE NAME
  2338. */
  2339. if ( (p = wcsrchr( DomainAndUsername, L'\\' )) != NULL ) {
  2340. /*
  2341. * Make sure that this user belongs to specified
  2342. * server.
  2343. */
  2344. *p = L'\0';
  2345. if ( _wcsicmp( DomainAndUsername, &s_szServer[2] ) ) {
  2346. continue;
  2347. }
  2348. }
  2349. /*
  2350. * Allocate list element and insert this username into list.
  2351. */
  2352. if ( (pNewUser = (PUSERLIST)malloc(sizeof(USERLIST))) == NULL ) {
  2353. rc = ERROR_OUTOFMEMORY;
  2354. break;
  2355. }
  2356. pNewUser->pNext = NULL;
  2357. wcscpy(pNewUser->UserName, p+1);
  2358. TotalCharacters += wcslen(p+1) + 1;
  2359. if ( pUserListBase == NULL ) {
  2360. /*
  2361. * First item in list.
  2362. */
  2363. pUserListBase = pNewUser;
  2364. }
  2365. else {
  2366. PUSERLIST pPrevUserList, pUserList;
  2367. pPrevUserList = pUserList = pUserListBase;
  2368. for ( ; ; ) {
  2369. if ( wcscmp(pNewUser->UserName, pUserList->UserName) < 0 ) {
  2370. if ( pPrevUserList == pUserListBase ) {
  2371. /*
  2372. * Insert at beginning of list.
  2373. */
  2374. pUserListBase = pNewUser;
  2375. }
  2376. else {
  2377. /*
  2378. * Insert into middle or beginning of list.
  2379. */
  2380. pPrevUserList->pNext = pNewUser;
  2381. }
  2382. /*
  2383. * Link to next.
  2384. */
  2385. pNewUser->pNext = pUserList;
  2386. break;
  2387. }
  2388. else if ( pUserList->pNext == NULL ) {
  2389. /*
  2390. * Add to end of list.
  2391. */
  2392. pUserList->pNext = pNewUser;
  2393. break;
  2394. }
  2395. pPrevUserList = pUserList;
  2396. pUserList = pUserList->pNext;
  2397. }
  2398. }
  2399. }
  2400. /*
  2401. * Free memory
  2402. */
  2403. if ( plgrmi3 != NULL ) {
  2404. NetApiBufferFree( plgrmi3 );
  2405. }
  2406. } while ( rc == ERROR_MORE_DATA );
  2407. /*
  2408. * Allocate buffer for multi-string compare list if no error so far
  2409. * and terminate in case of empty list.
  2410. */
  2411. if ( rc == ERROR_SUCCESS ) {
  2412. pszCompareList = (WCHAR *)malloc( (++TotalCharacters) * 2 );
  2413. if( pszCompareList != NULL )
  2414. {
  2415. *pszCompareList = L'\0';
  2416. }
  2417. }
  2418. /*
  2419. * Traverse and free username list, creating the multi-string compare
  2420. * list if buffer is available (no error so far).
  2421. */
  2422. if ( pUserListBase ) {
  2423. PUSERLIST pUserList = pUserListBase,
  2424. pNext = NULL;
  2425. WCHAR *pBuffer = pszCompareList;
  2426. do {
  2427. pNext = pUserList->pNext;
  2428. if ( pBuffer ) {
  2429. wcscpy(pBuffer, pUserList->UserName);
  2430. pBuffer += (wcslen(pBuffer) + 1);
  2431. *pBuffer = L'\0'; // auto double-null terminate
  2432. }
  2433. free(pUserList);
  2434. pUserList = pNext;
  2435. } while ( pUserList );
  2436. }
  2437. return(pszCompareList);
  2438. }
  2439. /*******************************************************************************
  2440. *
  2441. * GetUserFromSid - Hydrix helper function
  2442. *
  2443. * Fetch the user name associated with the specified SID.
  2444. *
  2445. * ENTRY:
  2446. * pSid (input)
  2447. * Points to SID to match to user name.
  2448. * pUserName (output)
  2449. * Points to buffer to place the user name into.
  2450. * cbUserName (input)
  2451. * Specifies the size in bytes of the user name buffer. The returned
  2452. * user name will be truncated to fit this buffer (including NUL
  2453. * terminator) if necessary.
  2454. *
  2455. * EXIT:
  2456. *
  2457. * GetUserFromSid() will always return a user name. If the specified
  2458. * SID fails to match to a user name, then the user name "(unknown)" will
  2459. * be returned.
  2460. *
  2461. ******************************************************************************/
  2462. void WINAPI
  2463. GetUserFromSid( PSID pSid,
  2464. LPTSTR pUserName,
  2465. DWORD cbUserName )
  2466. {
  2467. TCHAR DomainBuffer[DOMAIN_LENGTH], UserBuffer[USERNAME_LENGTH];
  2468. DWORD cbDomainBuffer=sizeof(DomainBuffer), cbUserBuffer=sizeof(UserBuffer),
  2469. Error;
  2470. LPTSTR pDomainBuffer = NULL, pUserBuffer = NULL;
  2471. SID_NAME_USE SidNameUse;
  2472. /*
  2473. * Fetch user name from SID: try user lookup with a reasonable Domain and
  2474. * Sid buffer size first, before resorting to alloc.
  2475. */
  2476. if ( !LookupAccountSid( NULL, pSid,
  2477. UserBuffer, &cbUserBuffer,
  2478. DomainBuffer, &cbDomainBuffer, &SidNameUse ) ) {
  2479. if ( ((Error = GetLastError()) == ERROR_INSUFFICIENT_BUFFER) ) {
  2480. if ( cbDomainBuffer > sizeof(DomainBuffer) ) {
  2481. if ( !(pDomainBuffer =
  2482. (LPTSTR)LocalAlloc(
  2483. LPTR, cbDomainBuffer * sizeof(TCHAR))) ) {
  2484. Error = ERROR_NOT_ENOUGH_MEMORY;
  2485. goto BadDomainAlloc;
  2486. }
  2487. }
  2488. if ( cbUserBuffer > sizeof(UserBuffer) ) {
  2489. if ( !(pUserBuffer =
  2490. (LPTSTR)LocalAlloc(
  2491. LPTR, cbUserBuffer * sizeof(TCHAR))) ) {
  2492. Error = ERROR_NOT_ENOUGH_MEMORY;
  2493. goto BadUserAlloc;
  2494. }
  2495. }
  2496. if ( !LookupAccountSid( NULL, pSid,
  2497. pUserBuffer ?
  2498. pUserBuffer : UserBuffer,
  2499. &cbUserBuffer,
  2500. pDomainBuffer ?
  2501. pDomainBuffer : DomainBuffer,
  2502. &cbDomainBuffer,
  2503. &SidNameUse ) ) {
  2504. Error = GetLastError();
  2505. goto BadLookup;
  2506. }
  2507. }
  2508. else {
  2509. goto BadLookup;
  2510. }
  2511. }
  2512. /*
  2513. * Copy the user name into the specified buffer, truncating if necessary,
  2514. * and make lower case.
  2515. */
  2516. lstrncpy( pUserName, pUserBuffer ? pUserBuffer : UserBuffer,
  2517. cbUserName - 1 );
  2518. pUserName[cbUserName-1] = TEXT('\0');
  2519. lstrlwr(pUserName);
  2520. /*
  2521. * Free our local allocs (if any) and return.
  2522. */
  2523. if ( pDomainBuffer )
  2524. LocalFree(pDomainBuffer);
  2525. if ( pUserBuffer )
  2526. LocalFree(pUserBuffer);
  2527. return;
  2528. /*--------------------------------------
  2529. * Error clean-up and return...
  2530. */
  2531. BadLookup:
  2532. BadUserAlloc:
  2533. BadDomainAlloc:
  2534. if ( pDomainBuffer )
  2535. LocalFree(pDomainBuffer);
  2536. if ( pUserBuffer )
  2537. LocalFree(pUserBuffer);
  2538. LoadString( GetModuleHandle( UTILDLL_NAME ),
  2539. IDS_UNKNOWN, pUserName, cbUserName - 1 );
  2540. pUserName[cbUserName-1] = TEXT('\0');
  2541. return;
  2542. } // end GetUserFromSid
  2543. /*******************************************************************************
  2544. *
  2545. * CachedGetUserFromSid - Hydrix helper function
  2546. *
  2547. * Provides entry point for a direct call to the UTILSUB.LIB
  2548. * GetUserNameFromSid, which performs its own caching of usernames.
  2549. *
  2550. * ENTRY:
  2551. * See UTILSUB.LIB GetUserNameFromSid (procutil.c)
  2552. * EXIT:
  2553. * See UTILSUB.LIB GetUserNameFromSid (procutil.c)
  2554. *
  2555. ******************************************************************************/
  2556. void WINAPI
  2557. CachedGetUserFromSid( PSID pSid,
  2558. PWCHAR pUserName,
  2559. PULONG pcbUserName )
  2560. {
  2561. GetUserNameFromSid( pSid, pUserName, pcbUserName );
  2562. } // end CachedGetUserFromSid
  2563. /*****************************************************************************
  2564. *
  2565. * TestUserForAdmin - Hydrix helper function
  2566. *
  2567. * Returns whether the current thread is running under admin
  2568. * security.
  2569. *
  2570. * ENTRY:
  2571. * dom (input)
  2572. * TRUE/FALSE - whether we want DOMAIN admin (as compared to local admin)
  2573. *
  2574. * EXIT:
  2575. * TRUE/FALSE - whether user is specified admin
  2576. *
  2577. ****************************************************************************/
  2578. BOOL WINAPI
  2579. TestUserForAdmin( BOOL dom )
  2580. {
  2581. BOOL IsMember, IsAnAdmin;
  2582. SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
  2583. PSID AdminSid;
  2584. if (RtlAllocateAndInitializeSid(
  2585. &SystemSidAuthority,
  2586. 2,
  2587. SECURITY_BUILTIN_DOMAIN_RID,
  2588. DOMAIN_ALIAS_RID_ADMINS,
  2589. 0, 0, 0, 0, 0, 0,
  2590. &AdminSid
  2591. ) != STATUS_SUCCESS)
  2592. {
  2593. IsAnAdmin = FALSE;
  2594. }
  2595. else
  2596. {
  2597. if (!CheckTokenMembership( NULL,
  2598. AdminSid,
  2599. &IsMember))
  2600. {
  2601. RtlFreeSid(AdminSid);
  2602. IsAnAdmin = FALSE;
  2603. }
  2604. else
  2605. {
  2606. RtlFreeSid(AdminSid);
  2607. IsAnAdmin = IsMember;
  2608. }
  2609. }
  2610. return IsAnAdmin;
  2611. // UNUSED dom;
  2612. } // end of TestUserForAdmin
  2613. /*****************************************************************************
  2614. *
  2615. * IsPartOfDomain - Hydrix helper function
  2616. *
  2617. * Returns whether the current server participates in a domain.
  2618. *
  2619. * ENTRY:
  2620. *
  2621. * EXIT:
  2622. * TRUE or FALSE
  2623. *
  2624. ****************************************************************************/
  2625. BOOL WINAPI
  2626. IsPartOfDomain(VOID)
  2627. {
  2628. NTSTATUS Status;
  2629. LSA_HANDLE PolicyHandle;
  2630. PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo;
  2631. OBJECT_ATTRIBUTES ObjAttributes;
  2632. BOOL IsDomainName = FALSE;
  2633. //
  2634. // Open a handle to the local security policy. Initialize the
  2635. // objects attributes structure first.
  2636. //
  2637. InitializeObjectAttributes( &ObjAttributes, NULL, 0, NULL, NULL );
  2638. Status = LsaOpenPolicy( NULL,
  2639. &ObjAttributes,
  2640. POLICY_VIEW_LOCAL_INFORMATION,
  2641. &PolicyHandle );
  2642. if ( !NT_SUCCESS(Status) )
  2643. goto done;
  2644. //
  2645. // Get the name of the primary domain from LSA
  2646. //
  2647. Status = LsaQueryInformationPolicy( PolicyHandle,
  2648. PolicyPrimaryDomainInformation,
  2649. (PVOID *)&DomainInfo );
  2650. (void) LsaClose( PolicyHandle );
  2651. if ( !NT_SUCCESS(Status) )
  2652. goto done;
  2653. if ( DomainInfo->DomainSid )
  2654. IsDomainName = TRUE;
  2655. (void) LsaFreeMemory( DomainInfo );
  2656. done:
  2657. return( IsDomainName );
  2658. } // end IsPartOfDomain
  2659. /*******************************************************************************
  2660. *
  2661. * StrSdClass - Hydrix helper function
  2662. *
  2663. * Returns pointer to string representing the specified SdClass.
  2664. *
  2665. * ENTRY:
  2666. * SdClass (input)
  2667. * The SDCLASS to associate with a string.
  2668. *
  2669. * EXIT:
  2670. * (LPCTSTR) Points to string representing the SDCLASS.
  2671. *
  2672. ******************************************************************************/
  2673. LPTSTR SdClassStrings[9] = { NULL};
  2674. LPCTSTR WINAPI
  2675. StrSdClass( SDCLASS SdClass )
  2676. {
  2677. TCHAR buffer[256];
  2678. WORD wID = IDS_UNKNOWN_PROTOCOL;
  2679. switch ( SdClass ) {
  2680. case SdConsole:
  2681. wID = IDS_CONSOLE;
  2682. break;
  2683. case SdNetwork:
  2684. wID = IDS_NETWORK;
  2685. break;
  2686. case SdAsync:
  2687. wID = IDS_ASYNC;
  2688. break;
  2689. case SdFrame:
  2690. wID = IDS_FRAME;
  2691. break;
  2692. case SdReliable:
  2693. wID = IDS_RELIABLE;
  2694. break;
  2695. case SdCompress:
  2696. wID = IDS_COMPRESSION;
  2697. break;
  2698. case SdEncrypt:
  2699. wID = IDS_ENCRYPTION;
  2700. break;
  2701. case SdTelnet:
  2702. wID = IDS_TELNET;
  2703. break;
  2704. }
  2705. // If we haven't loaded the string yet, do it now
  2706. if (!SdClassStrings[wID - IDS_CONSOLE]) {
  2707. LoadString(GetModuleHandle( UTILDLL_NAME ),
  2708. wID, buffer, lengthof(buffer) );
  2709. SdClassStrings[wID - IDS_CONSOLE] = LocalAlloc(LPTR, 2*(wcslen(buffer)+1));
  2710. if(NULL == SdClassStrings[wID - IDS_CONSOLE])
  2711. {
  2712. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2713. return NULL;
  2714. }
  2715. lstrcpy(SdClassStrings[wID - IDS_CONSOLE], buffer);
  2716. }
  2717. return(SdClassStrings[wID]);
  2718. } // end StrSdClass
  2719. /*******************************************************************************
  2720. *
  2721. * StrConnectState - Hydrix helper function
  2722. *
  2723. * Returns pointer to string representing the specified WinStation
  2724. * connection state.
  2725. *
  2726. * ENTRY:
  2727. * ConnectState (input)
  2728. * The WinStation connect state to associate with a string.
  2729. * bShortString (input)
  2730. * If TRUE, returns a short(er) version of the string (if there is
  2731. * one); FALSE returns the full spelling.
  2732. *
  2733. * EXIT:
  2734. * (LPCTSTR) Points to string representing the connect state.
  2735. *
  2736. * Note: The short version of the string may be the same as the long version.
  2737. * (i.e. "active") However, there are two string resources in case
  2738. * the long version of the string is not short in a language other
  2739. * than English.
  2740. ******************************************************************************/
  2741. LPTSTR ConnectStateStrings[21] = { NULL};
  2742. LPCTSTR WINAPI
  2743. StrConnectState( WINSTATIONSTATECLASS ConnectState,
  2744. BOOL bShortString )
  2745. {
  2746. TCHAR buffer[256];
  2747. WORD wID = IDS_UNKNOWN;
  2748. switch ( ConnectState ) {
  2749. case State_Active:
  2750. wID = bShortString ? IDS_SHORT_ACTIVE : IDS_ACTIVE;
  2751. break;
  2752. case State_Connected:
  2753. wID = bShortString ? IDS_SHORT_CONNECTED : IDS_CONNECTED;
  2754. break;
  2755. case State_ConnectQuery:
  2756. wID = bShortString ? IDS_SHORT_CONNECT_QUERY : IDS_CONNECT_QUERY;
  2757. break;
  2758. case State_Shadow:
  2759. wID = bShortString ? IDS_SHORT_SHADOW : IDS_SHADOW;
  2760. break;
  2761. case State_Disconnected:
  2762. wID = bShortString ? IDS_SHORT_DISCONNECTED : IDS_DISCONNECTED;
  2763. break;
  2764. case State_Idle:
  2765. wID = bShortString ? IDS_SHORT_IDLE : IDS_IDLE;
  2766. break;
  2767. case State_Reset:
  2768. wID = bShortString ? IDS_SHORT_RESET : IDS_RESET;
  2769. break;
  2770. case State_Down:
  2771. wID = bShortString ? IDS_SHORT_DOWN : IDS_DOWN;
  2772. break;
  2773. case State_Init:
  2774. wID = bShortString ? IDS_SHORT_INIT : IDS_INIT;
  2775. break;
  2776. case State_Listen:
  2777. wID = bShortString ? IDS_SHORT_LISTEN : IDS_LISTEN;
  2778. break;
  2779. }
  2780. // If we haven't loaded the string yet, do it now
  2781. if (!ConnectStateStrings[wID - IDS_ACTIVE]) {
  2782. LoadString(GetModuleHandle( UTILDLL_NAME ),
  2783. wID, buffer, lengthof(buffer) );
  2784. ConnectStateStrings[wID - IDS_ACTIVE] = LocalAlloc(LPTR, 2*(wcslen(buffer)+1));
  2785. if(NULL == ConnectStateStrings[wID - IDS_ACTIVE])
  2786. {
  2787. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2788. return NULL;
  2789. }
  2790. lstrcpy(ConnectStateStrings[wID - IDS_ACTIVE], buffer);
  2791. }
  2792. return(ConnectStateStrings[wID - IDS_ACTIVE]);
  2793. } // end StrConnectState
  2794. /*******************************************************************************
  2795. *
  2796. * StrProcessState - Hydrix helper function
  2797. *
  2798. * Returns pointer to string representing the specified process state.
  2799. *
  2800. * ENTRY:
  2801. * State (input)
  2802. * The process state to associate with a string.
  2803. *
  2804. * EXIT:
  2805. * (LPCTSTR) Points to string representing the process state.
  2806. *
  2807. ******************************************************************************/
  2808. LPTSTR ProcessStateStrings[8] = { NULL};
  2809. WORD StateTable[] = {
  2810. IDS_INITED,
  2811. IDS_READY,
  2812. IDS_RUN,
  2813. IDS_STANDBY,
  2814. IDS_TERMINATE,
  2815. IDS_WAIT,
  2816. IDS_TRANSIT,
  2817. IDS_STATE_DASHES,
  2818. IDS_STATE_DASHES,
  2819. IDS_STATE_DASHES,
  2820. IDS_STATE_DASHES,
  2821. IDS_STATE_DASHES
  2822. };
  2823. LPCTSTR WINAPI
  2824. StrProcessState( ULONG State )
  2825. {
  2826. TCHAR buffer[256];
  2827. WORD wID = StateTable[State];
  2828. // If we haven't loaded the string yet, do it now
  2829. if (!ProcessStateStrings[wID - IDS_INITED]) {
  2830. LoadString(GetModuleHandle( UTILDLL_NAME ),
  2831. wID, buffer, lengthof(buffer) );
  2832. ProcessStateStrings[wID - IDS_INITED] = LocalAlloc(LPTR, 2*(wcslen(buffer)+1));
  2833. if(NULL == ProcessStateStrings[wID - IDS_INITED])
  2834. {
  2835. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2836. return NULL;
  2837. }
  2838. lstrcpy(ProcessStateStrings[wID - IDS_INITED], buffer);
  2839. }
  2840. return(ProcessStateStrings[wID - IDS_INITED]);
  2841. } // end StrProcessState
  2842. /*******************************************************************************
  2843. *
  2844. * StrSystemWaitReason - Hydrix helper function
  2845. *
  2846. * Returns pointer to string representing the specified 'system'
  2847. * wait reason code.
  2848. *
  2849. * ENTRY:
  2850. * WaitReason (input)
  2851. * The system wait reason code to associate with a string.
  2852. *
  2853. * EXIT:
  2854. * (LPCTSTR) Points to string representing the system wait reason.
  2855. *
  2856. ******************************************************************************/
  2857. LPTSTR SystemWaitStrings[31] = { NULL};
  2858. WORD SystemWaitReason[] = {
  2859. IDS_EXECUTIVE, // Executive
  2860. IDS_FREE_PAGE, // FreePage
  2861. IDS_PAGE_IN, // PageIn
  2862. IDS_POOL_ALLOC, // PoolAlloc
  2863. IDS_DELAY_EXECUTION, // DelayExecution
  2864. IDS_SUSPENDED, // Suspended
  2865. IDS_USER_REQUEST, // UserRequest
  2866. IDS_EXECUTIVE, // Executive
  2867. IDS_FREE_PAGE, // FreePage
  2868. IDS_PAGE_IN, // PageIn
  2869. IDS_POOL_ALLOC, // PoolAllocation
  2870. IDS_DELAY_EXECUTION, // DelayExecution
  2871. IDS_SUSPENDED, // Suspended
  2872. IDS_USER_REQUEST, // UserRequest
  2873. IDS_EVENT_PAIR_HIGH, // EventPairHigh
  2874. IDS_EVENT_PAIR_LOW, // EventPairLow
  2875. IDS_LPC_RECEIVE, // LpcReceive
  2876. IDS_LPC_REPLY, // LpcReply
  2877. IDS_VIRTUAL_MEMORY, // VirtualMemory
  2878. IDS_PAGE_OUT, // PageOut
  2879. IDS_WAIT1,
  2880. IDS_WAIT2,
  2881. IDS_WAIT3,
  2882. IDS_WAIT4,
  2883. IDS_WAIT5,
  2884. IDS_WAIT6,
  2885. IDS_WAIT7,
  2886. IDS_WAIT8,
  2887. IDS_WAIT9,
  2888. IDS_WAIT10
  2889. };
  2890. LPCTSTR WINAPI
  2891. StrSystemWaitReason( ULONG WaitReason )
  2892. {
  2893. TCHAR buffer[256];
  2894. WORD wID = SystemWaitReason[WaitReason];
  2895. // If we haven't loaded the string yet, do it now
  2896. if (!SystemWaitStrings[wID - IDS_EXECUTIVE]) {
  2897. LoadString(GetModuleHandle( UTILDLL_NAME ),
  2898. wID, buffer, lengthof(buffer) );
  2899. SystemWaitStrings[wID - IDS_EXECUTIVE] = LocalAlloc(LPTR, 2*(wcslen(buffer)+1));
  2900. if(NULL == SystemWaitStrings[wID - IDS_EXECUTIVE])
  2901. {
  2902. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2903. return NULL;
  2904. }
  2905. wcscpy(SystemWaitStrings[wID - IDS_EXECUTIVE], buffer);
  2906. }
  2907. return(SystemWaitStrings[wID - IDS_EXECUTIVE]);
  2908. } // end StrSystemWaitReason
  2909. /*******************************************************************************
  2910. *
  2911. * StrAsyncConnectState - Hydrix helper function
  2912. *
  2913. * Returns pointer to string representing the specified async connect state.
  2914. *
  2915. * ENTRY:
  2916. * State (input)
  2917. * The async connect state to associate with a string.
  2918. *
  2919. * EXIT:
  2920. * (LPCTSTR) Points to string representing the async connect state.
  2921. *
  2922. ******************************************************************************/
  2923. LPTSTR AsyncConnectStateStrings[6] = { NULL };
  2924. LPCTSTR WINAPI
  2925. StrAsyncConnectState( ASYNCCONNECTCLASS State )
  2926. {
  2927. TCHAR buffer[256];
  2928. WORD wID = State - Connect_CTS;
  2929. // If we haven't loaded the string yet, do it now
  2930. if (!AsyncConnectStateStrings[wID]) {
  2931. LoadString(GetModuleHandle( UTILDLL_NAME ),
  2932. wID + IDS_ASYNC_CONNECT_CTS, buffer, lengthof(buffer) );
  2933. AsyncConnectStateStrings[wID] = LocalAlloc(LPTR, 2*(wcslen(buffer)+1));
  2934. if(NULL == AsyncConnectStateStrings[wID])
  2935. {
  2936. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2937. return NULL;
  2938. }
  2939. lstrcpy(AsyncConnectStateStrings[wID], buffer);
  2940. }
  2941. return(AsyncConnectStateStrings[wID]);
  2942. } // end StrProcessState
  2943. /*******************************************************************************
  2944. *
  2945. * GetUnknownString - Hydrix helper function
  2946. *
  2947. * Returns pointer to the string representing an unknown
  2948. * Connect State or DateTimeString (IDS_UNKNOWN)
  2949. * This is primarily so that WinAdmin can compare against it
  2950. *
  2951. * ENTRY:
  2952. * None
  2953. *
  2954. * EXIT:
  2955. * (LPCTSTR) Points to string representing the unknown string
  2956. *
  2957. ******************************************************************************/
  2958. LPTSTR UnknownString = NULL;
  2959. LPCTSTR WINAPI
  2960. GetUnknownString()
  2961. {
  2962. TCHAR buffer[256];
  2963. // if we haven't loaded the string yet, do it now
  2964. if (!UnknownString) {
  2965. LoadString(GetModuleHandle( UTILDLL_NAME ),
  2966. IDS_UNKNOWN, buffer, lengthof(buffer) );
  2967. UnknownString = LocalAlloc(LPTR, 2*(wcslen(buffer)+1));
  2968. if(NULL == UnknownString)
  2969. {
  2970. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2971. return NULL;
  2972. }
  2973. lstrcpy(UnknownString, buffer);
  2974. }
  2975. return(UnknownString);
  2976. } // end GetUnknownString
  2977. /*******************************************************************************
  2978. *
  2979. * CalculateElapsedTime - Hydrix helper function
  2980. *
  2981. * Determines the difference between a specified LARGE_INTEGER time value
  2982. * and the current system time, saves this 'elapsed time' into the
  2983. * specified ELAPSEDTIME structure.
  2984. *
  2985. * ENTRY:
  2986. * pTime (input)
  2987. * Points to LARGE_INTEGER of time for difference calculation.
  2988. * pElapsedTime (output)
  2989. * Points to ELAPSEDTIME structure to save elapsed time.
  2990. *
  2991. * EXIT:
  2992. *
  2993. ******************************************************************************/
  2994. void WINAPI
  2995. CalculateElapsedTime( LARGE_INTEGER *pTime,
  2996. ELAPSEDTIME *pElapsedTime )
  2997. {
  2998. LARGE_INTEGER InputTime;
  2999. LARGE_INTEGER CurrentTime;
  3000. LARGE_INTEGER DiffTime;
  3001. SYSTEMTIME ltime;
  3002. ULONG d_time;
  3003. /*
  3004. * Fetch the current time and zero out the specified ELAPSEDTIME structure.
  3005. */
  3006. GetLocalTime( &ltime );
  3007. memset( pElapsedTime, 0, sizeof(ELAPSEDTIME) );
  3008. if ( (pTime->HighPart == 0 && pTime->LowPart == 0 ) ||
  3009. !FileTimeToLocalFileTime( (FILETIME*)pTime, (FILETIME*)&InputTime ) ||
  3010. !SystemTimeToFileTime( &ltime, (FILETIME *)&CurrentTime ) )
  3011. return;
  3012. /*
  3013. * Get the number of seconds since specified time.
  3014. */
  3015. DiffTime = CalculateDiffTime( InputTime, CurrentTime );
  3016. d_time = DiffTime.LowPart;
  3017. /*
  3018. * Calculate the days, hours, minutes, seconds since specified time.
  3019. */
  3020. pElapsedTime->days = (USHORT)(d_time / 86400L); // days since
  3021. d_time = d_time % 86400L; // seconds => partial day
  3022. pElapsedTime->hours = (USHORT)(d_time / 3600L); // hours since
  3023. d_time = d_time % 3600L; // seconds => partial hour
  3024. pElapsedTime->minutes = (USHORT)(d_time / 60L); // minutes since
  3025. pElapsedTime->seconds = (USHORT)(d_time % 60L); // seconds remaining
  3026. } // end CalculateElapsedTime
  3027. /*******************************************************************************
  3028. *
  3029. * CompareElapsedTime - Hydrix helper function
  3030. *
  3031. * Determines the difference between two ELAPSEDTIME values.
  3032. *
  3033. * ENTRY:
  3034. * pElapsedTime1 (input)
  3035. * Points to first ELAPSEDTIME
  3036. * pElapsedTime2 (input)
  3037. * Points to ELAPSEDTIME structure to save elapsed time.
  3038. * bCompareSeconds (input)
  3039. * TRUE to include the seconds member in comparison; false otherwise.
  3040. *
  3041. * EXIT:
  3042. * < 1 if first time is less than second time
  3043. * 0 if times are the same
  3044. * > 1 if first time is greater than second time
  3045. *
  3046. ******************************************************************************/
  3047. int WINAPI
  3048. CompareElapsedTime( ELAPSEDTIME *pElapsedTime1,
  3049. ELAPSEDTIME *pElapsedTime2,
  3050. BOOL bCompareSeconds )
  3051. {
  3052. int result;
  3053. if ( !(result = pElapsedTime1->days - pElapsedTime2->days) &&
  3054. !(result = pElapsedTime1->hours - pElapsedTime2->hours) &&
  3055. !(result = pElapsedTime1->minutes - pElapsedTime2->minutes) &&
  3056. (!bCompareSeconds ||
  3057. !(result = pElapsedTime1->seconds - pElapsedTime2->seconds) ) )
  3058. return(0);
  3059. else
  3060. return(result);
  3061. } // end CompareElapsedTime
  3062. /*******************************************************************************
  3063. *
  3064. * ElapsedTimeString - Hydrix helper function
  3065. *
  3066. * Converts the specified ELAPSEDTIME into a string of the form
  3067. * "ddd+hh:mm:ss" or, optionally "ddd+hh:mm" (suppress seconds).
  3068. *
  3069. * ENTRY:
  3070. * pElapsedTime (input)
  3071. * Points to ELAPSEDTIME structure to convert to string.
  3072. * bIncludeSeconds (input)
  3073. * If TRUE, will include seconds in string; FALSE will exclude.
  3074. * pString (output)
  3075. * Points to location to store elapsed time string.
  3076. * EXIT:
  3077. *
  3078. ******************************************************************************/
  3079. void WINAPI
  3080. ElapsedTimeString( ELAPSEDTIME *pElapsedTime,
  3081. BOOL bIncludeSeconds,
  3082. LPTSTR pString )
  3083. {
  3084. if ( bIncludeSeconds ) {
  3085. if ( pElapsedTime->days > 0 )
  3086. wsprintf( pString, TEXT("%u+%02u:%02u:%02u"),
  3087. pElapsedTime->days,
  3088. pElapsedTime->hours,
  3089. pElapsedTime->minutes,
  3090. pElapsedTime->seconds );
  3091. else if ( pElapsedTime->hours > 0 )
  3092. wsprintf( pString, TEXT("%u:%02u:%02u"),
  3093. pElapsedTime->hours,
  3094. pElapsedTime->minutes,
  3095. pElapsedTime->seconds );
  3096. else if ( pElapsedTime->minutes > 0 )
  3097. wsprintf( pString, TEXT("%u:%02u"),
  3098. pElapsedTime->minutes,
  3099. pElapsedTime->seconds );
  3100. else if ( pElapsedTime->seconds > 0 )
  3101. wsprintf( pString, TEXT("%u"),
  3102. pElapsedTime->seconds );
  3103. else
  3104. wsprintf( pString, TEXT(".") );
  3105. }
  3106. else {
  3107. if ( pElapsedTime->days > 0 )
  3108. wsprintf( pString, TEXT("%u+%02u:%02u"),
  3109. pElapsedTime->days,
  3110. pElapsedTime->hours,
  3111. pElapsedTime->minutes );
  3112. else if ( pElapsedTime->hours > 0 )
  3113. wsprintf( pString, TEXT("%u:%02u"),
  3114. pElapsedTime->hours,
  3115. pElapsedTime->minutes );
  3116. else if ( pElapsedTime->minutes > 0 )
  3117. wsprintf( pString, TEXT("%u"),
  3118. pElapsedTime->minutes );
  3119. else
  3120. wsprintf( pString, TEXT(".") );
  3121. }
  3122. } // end ElapsedTimeString
  3123. /*******************************************************************************
  3124. *
  3125. * DateTimeString - Hydrix helper function
  3126. *
  3127. * Converts the specified LARGE_INTEGER time value into a date/time string
  3128. * of the form "mm/dd/yy hh:mm".
  3129. *
  3130. * ENTRY:
  3131. * pTime (input)
  3132. * Points to LARGE_INTEGER of time to convert to string.
  3133. * pString (output)
  3134. * Points string to store converted date/time into.
  3135. *
  3136. * EXIT:
  3137. *
  3138. ******************************************************************************/
  3139. void WINAPI
  3140. DateTimeString( LARGE_INTEGER *pTime,
  3141. LPTSTR pString )
  3142. {
  3143. FILETIME LocalTime;
  3144. SYSTEMTIME stime;
  3145. LPTSTR lpTimeStr;
  3146. int nLen;
  3147. if ( FileTimeToLocalFileTime( (FILETIME *)pTime, &LocalTime ) &&
  3148. FileTimeToSystemTime( &LocalTime, &stime ) ) {
  3149. //Get Date Format
  3150. nLen = GetDateFormat(
  3151. LOCALE_USER_DEFAULT,
  3152. DATE_SHORTDATE,
  3153. &stime,
  3154. NULL,
  3155. NULL,
  3156. 0);
  3157. lpTimeStr = (LPTSTR) GlobalAlloc(GPTR, (nLen + 1) * sizeof(TCHAR));
  3158. if(NULL == lpTimeStr)
  3159. {
  3160. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3161. wcscpy(pString, L"");
  3162. return;
  3163. }
  3164. nLen = GetDateFormat(
  3165. LOCALE_USER_DEFAULT,
  3166. DATE_SHORTDATE,
  3167. &stime,
  3168. NULL,
  3169. lpTimeStr,
  3170. nLen);
  3171. wcscpy(pString, lpTimeStr);
  3172. wcscat(pString, L" ");
  3173. GlobalFree(lpTimeStr);
  3174. //Get Time Format
  3175. nLen = GetTimeFormat(
  3176. LOCALE_USER_DEFAULT,
  3177. TIME_NOSECONDS,
  3178. &stime,
  3179. NULL,
  3180. NULL,
  3181. 0);
  3182. lpTimeStr = (LPTSTR) GlobalAlloc(GPTR, (nLen + 1) * sizeof(TCHAR));
  3183. if(NULL == lpTimeStr)
  3184. {
  3185. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3186. wcscpy(pString, L"");
  3187. return;
  3188. }
  3189. nLen = GetTimeFormat(
  3190. LOCALE_USER_DEFAULT,
  3191. TIME_NOSECONDS,
  3192. &stime,
  3193. NULL,
  3194. lpTimeStr,
  3195. nLen);
  3196. wcscat(pString, lpTimeStr);
  3197. GlobalFree(lpTimeStr);
  3198. }
  3199. else
  3200. LoadString( GetModuleHandle( UTILDLL_NAME ),
  3201. IDS_UNKNOWN, pString, lengthof(pString) );
  3202. } // end DateTimeString
  3203. /*******************************************************************************
  3204. *
  3205. * CurrentDateTimeString - Hydrix helper function
  3206. *
  3207. * Converts the current system time into a date/time string of the form
  3208. * "mm/dd/yy hh:mm".
  3209. *
  3210. * ENTRY:
  3211. * pString (output)
  3212. * Points string to store converted date/time into.
  3213. * EXIT:
  3214. *
  3215. ******************************************************************************/
  3216. void WINAPI
  3217. CurrentDateTimeString( LPTSTR pString )
  3218. {
  3219. SYSTEMTIME stime;
  3220. LPTSTR lpTimeStr;
  3221. int nLen;
  3222. GetLocalTime(&stime);
  3223. //Get DateFormat
  3224. nLen = GetDateFormat(
  3225. LOCALE_USER_DEFAULT,
  3226. DATE_SHORTDATE,
  3227. &stime,
  3228. NULL,
  3229. NULL,
  3230. 0);
  3231. lpTimeStr = (LPTSTR) GlobalAlloc(GPTR, (nLen + 1) * sizeof(TCHAR));
  3232. if(NULL == lpTimeStr)
  3233. {
  3234. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3235. wcscpy(pString, L"");
  3236. return;
  3237. }
  3238. nLen = GetDateFormat(
  3239. LOCALE_USER_DEFAULT,
  3240. DATE_SHORTDATE,
  3241. &stime,
  3242. NULL,
  3243. lpTimeStr,
  3244. nLen);
  3245. wcscpy(pString, lpTimeStr);
  3246. wcscat(pString, L" ");
  3247. GlobalFree(lpTimeStr);
  3248. //Get Time Format
  3249. nLen = GetTimeFormat(
  3250. LOCALE_USER_DEFAULT,
  3251. TIME_NOSECONDS,
  3252. &stime,
  3253. NULL,
  3254. NULL,
  3255. 0);
  3256. lpTimeStr = (LPTSTR) GlobalAlloc(GPTR, (nLen + 1) * sizeof(TCHAR));
  3257. if(NULL == lpTimeStr)
  3258. {
  3259. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3260. wcscpy(pString, L"");
  3261. return;
  3262. }
  3263. nLen = GetTimeFormat(
  3264. LOCALE_USER_DEFAULT,
  3265. TIME_NOSECONDS,
  3266. &stime,
  3267. NULL,
  3268. lpTimeStr,
  3269. nLen);
  3270. wcscat(pString, lpTimeStr);
  3271. GlobalFree(lpTimeStr);
  3272. } // end CurrentDateTimeString
  3273. /*******************************************************************************
  3274. *
  3275. * CalculateDiffTime - Hydrix helper function
  3276. *
  3277. * Calculate the time difference between two LARGE_INTEGER time values.
  3278. *
  3279. * ENTRY:
  3280. * FirstTime (input)
  3281. * The first (lower) time value.
  3282. * SecondTime (input)
  3283. * The second (higher) time value.
  3284. *
  3285. * EXIT:
  3286. * LARGE_INTEGER - the time difference
  3287. *
  3288. ******************************************************************************/
  3289. LARGE_INTEGER WINAPI
  3290. CalculateDiffTime( LARGE_INTEGER FirstTime, LARGE_INTEGER SecondTime )
  3291. {
  3292. LARGE_INTEGER DiffTime;
  3293. DiffTime = RtlLargeIntegerSubtract( SecondTime, FirstTime );
  3294. DiffTime = RtlExtendedLargeIntegerDivide( DiffTime, 10000000, NULL );
  3295. return(DiffTime);
  3296. } // end CalculateDiffTime
  3297. /*******************************************************************************
  3298. *
  3299. * EnumerateMultiUserServers - Hydrix helper function
  3300. *
  3301. * Enumerate the Hydrix servers on the network by Domain
  3302. *
  3303. * ENTRY:
  3304. * pDomain (input)
  3305. * Specifies the domain to enumerate; NULL for current domain.
  3306. *
  3307. * EXIT:
  3308. * (LPTSTR) Points to LocalAlloced buffer containing results of the
  3309. * enumeration, in multi-string format, if sucessful; NULL if
  3310. * error. The caller must perform a LocalFree of this buffer
  3311. * when done. If error (NULL), the error code is set for
  3312. * retrieval by GetLastError();
  3313. *
  3314. ******************************************************************************/
  3315. LPWSTR WINAPI
  3316. EnumerateMultiUserServers( LPWSTR pDomain )
  3317. {
  3318. PSERVER_INFO_101 pInfo = NULL;
  3319. DWORD dwByteCount, dwIndex, TotalEntries;
  3320. DWORD AvailCount = 0;
  3321. LPWSTR pTemp, pBuffer = NULL;
  3322. /*
  3323. * Enumerate all WF servers on the specified domain.
  3324. */
  3325. if ( NetServerEnum ( NULL,
  3326. 101,
  3327. (LPBYTE *)&pInfo,
  3328. (DWORD) -1,
  3329. &AvailCount,
  3330. &TotalEntries,
  3331. SV_TYPE_TERMINALSERVER,
  3332. pDomain,
  3333. NULL ) ||
  3334. !AvailCount )
  3335. goto done;
  3336. /*
  3337. * Traverse list and calculate the total byte count for list of
  3338. * servers that will be returned.
  3339. */
  3340. for ( dwByteCount = dwIndex = 0; dwIndex < AvailCount; dwIndex++ ) {
  3341. dwByteCount += (wcslen(pInfo[dwIndex].sv101_name) + 1) * 2;
  3342. }
  3343. dwByteCount += 2; // for ending null
  3344. /*
  3345. * Allocate memory.
  3346. */
  3347. if ( (pBuffer = LocalAlloc(LPTR, dwByteCount)) == NULL ) {
  3348. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3349. goto done;
  3350. }
  3351. /*
  3352. * Traverse list again and copy servers to buffer.
  3353. */
  3354. for ( pTemp = pBuffer, dwIndex = 0; dwIndex < AvailCount; dwIndex++ ) {
  3355. wcscpy(pTemp, pInfo[dwIndex].sv101_name);
  3356. pTemp += (wcslen(pInfo[dwIndex].sv101_name) + 1);
  3357. }
  3358. *pTemp = L'\0'; // ending null
  3359. done:
  3360. if ( AvailCount && pInfo )
  3361. NetApiBufferFree( pInfo );
  3362. return(pBuffer);
  3363. } // end EnumerateMultiUserServers
  3364. /******************************************************************************
  3365. *
  3366. * _UserInGroup
  3367. * Internal function, determines if a user is a member of any of the
  3368. * groups passed in
  3369. *
  3370. * ENTRY:
  3371. * pwszUsername (IN) - Username to test group membership of
  3372. *
  3373. * pwszDomain (IN) - Domain of the user passed in
  3374. *
  3375. * pwszGroup (IN) - String array of all the allowed groups
  3376. *
  3377. * EXIT:
  3378. * Returns BOOLEAN value if user is a member of one of the groups
  3379. * HISTORY:
  3380. *
  3381. *
  3382. *****************************************************************************/
  3383. BOOL _UserInGroup( LPWSTR pwszUsername, LPWSTR pwszDomain, LPWSTR pwszGroup )
  3384. {
  3385. DWORD EntriesRead;
  3386. DWORD EntriesLeft;
  3387. NET_API_STATUS rc;
  3388. PGROUP_USERS_INFO_0 pszGroups;
  3389. ULONG i;
  3390. PWCHAR pwcUser;
  3391. WCHAR szBuf[MAX_PATH];
  3392. LPWKSTA_INFO_100 pWorkstationInfo = NULL;
  3393. WCHAR szDomainController[50];
  3394. #if DBG
  3395. DbgPrint( "MSGINA: UserInGroup: look(%S\\%S) group(%S)\n",
  3396. pwszDomain, pwszUsername, pwszGroup );
  3397. #endif
  3398. // This call will return the domain of the computer, not the domain of the user
  3399. if (( NetWkstaGetInfo( NULL,
  3400. 100,
  3401. (LPBYTE *)&pWorkstationInfo )) == NERR_Success) {
  3402. if( !CtxGetAnyDCName( NULL,
  3403. pWorkstationInfo->wki100_langroup,
  3404. szDomainController ) ){
  3405. NetApiBufferFree((LPVOID)pWorkstationInfo);
  3406. return( FALSE );
  3407. }
  3408. }
  3409. else {
  3410. return (FALSE);
  3411. }
  3412. if ( wcscmp( pWorkstationInfo->wki100_langroup, pwszDomain ) != 0 ) {
  3413. // user is from a different domain than the machine (trusted domain)
  3414. // need to change username to reflect the domain
  3415. wcscpy( szBuf, pwszDomain );
  3416. wcscat( szBuf, L"\\" );
  3417. wcscat( szBuf, pwszUsername );
  3418. pwcUser = szBuf;
  3419. }
  3420. else {
  3421. pwcUser = pwszUsername;
  3422. }
  3423. rc = NetUserGetLocalGroups( szDomainController,
  3424. pwcUser,
  3425. 0, // level
  3426. LG_INCLUDE_INDIRECT, // flags
  3427. (LPBYTE*)&pszGroups,
  3428. MAX_BUFFER,
  3429. &EntriesRead,
  3430. &EntriesLeft );
  3431. if( pWorkstationInfo != NULL )
  3432. NetApiBufferFree((LPVOID)pWorkstationInfo);
  3433. if ( rc != NERR_Success ) {
  3434. return( FALSE );
  3435. }
  3436. for ( i=0; i < EntriesRead; i++ ) {
  3437. if ( wcscmp( pszGroups[i].grui0_name, pwszGroup ) == 0 ) {
  3438. NetApiBufferFree( pszGroups );
  3439. pszGroups = NULL;
  3440. return( TRUE );
  3441. }
  3442. }
  3443. NetApiBufferFree( pszGroups );
  3444. pszGroups = NULL;
  3445. return(FALSE);
  3446. }
  3447. /******************************************************************************
  3448. *
  3449. * CtxGetAnyDCName
  3450. * Function to find a any DC of a specified domain. The call
  3451. * NetGetAnyDCName does not work as needed in all occasions.
  3452. * ie. Trusted domains and the current server being a DC.
  3453. *
  3454. * ENTRY:
  3455. * pServer (IN) - Server on which to run the call (RPC)
  3456. *
  3457. * pDomain (IN) - Domain you are inquring about, does not need to be
  3458. * current domain
  3459. *
  3460. * pBuffer (OUT) - Pointer to a string containg a DC name, buffer must
  3461. * be passed in.
  3462. * EXIT:
  3463. * BOOL Success
  3464. *
  3465. * HISTORY:
  3466. *
  3467. *
  3468. *****************************************************************************/
  3469. BOOL
  3470. CtxGetAnyDCName ( PWCHAR pServer, PWCHAR pDomain, PWCHAR pBuffer )
  3471. {
  3472. PWCHAR pDomainController = NULL;
  3473. PWCHAR pLocalDomainDC = NULL;
  3474. SERVER_INFO_101* ServerBuf = NULL;
  3475. BOOLEAN rc = TRUE;
  3476. BOOLEAN bFoundDC = FALSE;
  3477. // This call will return the domain of the computer, not the domain of the user
  3478. if (( NetGetAnyDCName(NULL,
  3479. pDomain,
  3480. (LPBYTE *)&pDomainController)) != NERR_Success) {
  3481. //
  3482. // NetGetAnyDCName doesn't work in two situations
  3483. // 1. If the domain is a trusted domain, it must be run from a DC. So we find our local
  3484. // DC and have it run getanydcname for us.
  3485. // 2. If we are a DC it will fail. So a second check is made to see
  3486. // if in fact we are a DC or not
  3487. //
  3488. // find a local DC in which to RPC to
  3489. if( NetGetAnyDCName( NULL,
  3490. NULL,
  3491. (LPBYTE *) &pLocalDomainDC ) == NERR_Success ) {
  3492. // Make the call as an RPC and pass it the Domain name
  3493. if( NetGetAnyDCName( pLocalDomainDC,
  3494. pDomain,
  3495. (LPBYTE *) &pDomainController ) == NERR_Success){
  3496. bFoundDC = TRUE;
  3497. }
  3498. }
  3499. // if it wasn't a trusted domain, maybe we are a domain controller
  3500. if( !bFoundDC ) {
  3501. if( NetServerGetInfo( NULL,
  3502. 101,
  3503. (LPBYTE*)&ServerBuf ) == NERR_Success ) {
  3504. if( ServerBuf->sv101_type & (SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL) ) {
  3505. pDomainController = NULL;
  3506. }
  3507. else {
  3508. rc = FALSE;
  3509. goto done;
  3510. }
  3511. }
  3512. else {
  3513. rc = FALSE;
  3514. goto done;
  3515. }
  3516. }
  3517. }
  3518. if( pDomainController )
  3519. wcscpy( pBuffer, pDomainController);
  3520. else
  3521. *pBuffer = '\0';
  3522. done:
  3523. if( pLocalDomainDC )
  3524. NetApiBufferFree( pLocalDomainDC );
  3525. if( pDomainController )
  3526. NetApiBufferFree( pDomainController );
  3527. if( ServerBuf )
  3528. NetApiBufferFree( ServerBuf );
  3529. return( rc );
  3530. }