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

1812 lines
39 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. svcapis.cpp
  5. Abstract:
  6. This module implements routines to assist
  7. CUSTOM Mode Value SSR Knowledge Base processing.
  8. Author:
  9. Vishnu Patankar (VishnuP) - Oct 2001
  10. Environment:
  11. User mode only.
  12. Exported Functions:
  13. svcapis.def
  14. Revision History:
  15. Created - Oct 2001
  16. --*/
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #include <windows.h>
  21. #include <tchar.h>
  22. #include <comdef.h>
  23. #include <msxml2.h>
  24. #include <winsvc.h>
  25. #include <ntlsa.h>
  26. #include <Lmshare.h>
  27. #include <Lmapibuf.h>
  28. #include <lmerr.h>
  29. #include <winsta.h>
  30. #include <winsock2.h>
  31. #include <iphlpapi.h>
  32. #include <iptypes.h>
  33. #include <wbemcli.h>
  34. #include <atlbase.h>
  35. CComModule _Module;
  36. #include <atlcom.h>
  37. #include <regapi.h>
  38. #include <initguid.h>
  39. #include <ole2.h>
  40. #include <mstask.h>
  41. #include <msterr.h>
  42. #include <wchar.h>
  43. #include <dsrole.h>
  44. typedef DWORD (WINAPI *PFGETDOMAININFO)(LPCWSTR, DSROLE_PRIMARY_DOMAIN_INFO_LEVEL, PBYTE *);
  45. typedef VOID (WINAPI *PFDSFREE)( PVOID );
  46. typedef BOOLEAN (WINAPI *PFREMOTEASSISTANCEENABLED)(VOID);
  47. DWORD
  48. SvcapispQueryServiceStartupType(
  49. IN PWSTR pszMachineName,
  50. IN PWSTR pszServiceName,
  51. OUT BYTE *pbyStartupType
  52. );
  53. HRESULT
  54. SvcapispGetRemoteOSVersionInfo(
  55. IN PWSTR pszMachineName,
  56. OUT OSVERSIONINFOEX *posVersionInfo
  57. );
  58. BOOL WINAPI DllMain(
  59. IN HANDLE DllHandle,
  60. IN ULONG ulReason,
  61. IN LPVOID Reserved
  62. )
  63. /*++
  64. Routine Description:
  65. Typical DllMain functionality
  66. Arguments:
  67. DllHandle
  68. ulReason
  69. Reserved
  70. Return:
  71. TRUE if successfully initialized, FALSE otherwise
  72. --*/
  73. {
  74. switch(ulReason) {
  75. case DLL_PROCESS_ATTACH:
  76. //
  77. // Fall through to process first thread
  78. //
  79. case DLL_THREAD_ATTACH:
  80. break;
  81. case DLL_PROCESS_DETACH:
  82. break;
  83. case DLL_THREAD_DETACH:
  84. break;
  85. }
  86. return TRUE;
  87. }
  88. STDAPI DllRegisterServer(
  89. void
  90. )
  91. /*++
  92. Routine Description:
  93. Registers dll
  94. Arguments:
  95. Return:
  96. S_OK if successful
  97. --*/
  98. {
  99. return S_OK;
  100. }
  101. STDAPI
  102. DllUnregisterServer(
  103. void
  104. )
  105. /*++
  106. Routine Description:
  107. Unregisters dll
  108. Arguments:
  109. Return:
  110. S_OK if successful
  111. --*/
  112. {
  113. return S_OK;
  114. }
  115. DWORD
  116. SvcapispQueryServiceStartupType(
  117. IN PWSTR pszMachineName,
  118. IN PWSTR pszServiceName,
  119. OUT BYTE *pbyStartupType
  120. )
  121. /*++
  122. Routine Description:
  123. Routine called to check service startup type
  124. Arguments:
  125. pszMachineName - name of machine to evaluate function on
  126. pszServiceName - name of service
  127. pbyStartupType - startup type
  128. Return:
  129. Win32 error code
  130. ++*/
  131. {
  132. DWORD rc = ERROR_SUCCESS;
  133. DWORD dwBytesNeeded = 0;
  134. SC_HANDLE hService = NULL;
  135. LPQUERY_SERVICE_CONFIG pServiceConfig=NULL;
  136. SC_HANDLE hScm = NULL;
  137. if (pbyStartupType == NULL || pszServiceName == NULL){
  138. return ERROR_INVALID_PARAMETER;
  139. }
  140. *pbyStartupType = SERVICE_DISABLED;
  141. hScm = OpenSCManager(
  142. pszMachineName,
  143. NULL,
  144. GENERIC_READ);
  145. if (hScm == NULL) {
  146. rc = GetLastError();
  147. goto ExitHandler;
  148. }
  149. hService = OpenService(
  150. hScm,
  151. pszServiceName,
  152. SERVICE_QUERY_CONFIG |
  153. READ_CONTROL
  154. );
  155. if ( hService == NULL ) {
  156. rc = GetLastError();
  157. goto ExitHandler;
  158. }
  159. if ( !QueryServiceConfig(
  160. hService,
  161. NULL,
  162. 0,
  163. &dwBytesNeeded
  164. )) {
  165. if (ERROR_INSUFFICIENT_BUFFER != (rc = GetLastError())){
  166. goto ExitHandler;
  167. }
  168. }
  169. rc = ERROR_SUCCESS;
  170. pServiceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_ZEROINIT, dwBytesNeeded);
  171. if ( pServiceConfig == NULL ) {
  172. rc = ERROR_NOT_ENOUGH_MEMORY;
  173. goto ExitHandler;
  174. }
  175. if ( !QueryServiceConfig(
  176. hService,
  177. pServiceConfig,
  178. dwBytesNeeded,
  179. &dwBytesNeeded) )
  180. {
  181. rc = GetLastError();
  182. goto ExitHandler;
  183. }
  184. *pbyStartupType = (BYTE)(pServiceConfig->dwStartType) ;
  185. ExitHandler:
  186. if (pServiceConfig) {
  187. LocalFree(pServiceConfig);
  188. }
  189. if (hService) {
  190. CloseServiceHandle(hService);
  191. }
  192. if (hScm) {
  193. CloseServiceHandle(hScm);
  194. }
  195. return rc;
  196. }
  197. DWORD
  198. SvcapisIsDomainMember(
  199. IN PWSTR pszMachineName,
  200. OUT BOOL *pbIsDomainMember
  201. )
  202. /*++
  203. Routine Description:
  204. Detects if machine is joined to a domain
  205. Arguments:
  206. pszMachineName - name of machine to evaluate function on
  207. pbIsDomainMember - pointer to boolean to fill
  208. Return:
  209. Win32 error code
  210. --*/
  211. {
  212. NTSTATUS NtStatus;
  213. PPOLICY_DNS_DOMAIN_INFO pDnsDomainInfo=NULL;
  214. LSA_HANDLE LsaHandle=NULL;
  215. LSA_OBJECT_ATTRIBUTES attributes;
  216. SECURITY_QUALITY_OF_SERVICE service;
  217. UNICODE_STRING uMachineName;
  218. if (pbIsDomainMember == NULL) {
  219. return ERROR_INVALID_PARAMETER;
  220. }
  221. *pbIsDomainMember = FALSE;
  222. //
  223. // Open the LSA policy first
  224. //
  225. memset( &attributes, 0, sizeof(attributes) );
  226. attributes.Length = sizeof(attributes);
  227. attributes.SecurityQualityOfService = &service;
  228. service.Length = sizeof(service);
  229. service.ImpersonationLevel= SecurityImpersonation;
  230. service.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  231. service.EffectiveOnly = TRUE;
  232. RtlInitUnicodeString(&uMachineName, pszMachineName);
  233. NtStatus = LsaOpenPolicy(
  234. pszMachineName ? &uMachineName: NULL,
  235. &attributes,
  236. POLICY_VIEW_LOCAL_INFORMATION,
  237. &LsaHandle
  238. );
  239. if ( !NT_SUCCESS( NtStatus) ) {
  240. goto ExitHandler;
  241. }
  242. //
  243. // query primary domain DNS information
  244. //
  245. NtStatus = LsaQueryInformationPolicy(
  246. LsaHandle,
  247. PolicyDnsDomainInformation,
  248. (PVOID *)&pDnsDomainInfo
  249. );
  250. if ( !NT_SUCCESS( NtStatus) || pDnsDomainInfo == NULL) {
  251. goto ExitHandler;
  252. }
  253. if (pDnsDomainInfo->Sid){
  254. *pbIsDomainMember = TRUE;
  255. }
  256. ExitHandler:
  257. if (pDnsDomainInfo){
  258. LsaFreeMemory(pDnsDomainInfo);
  259. }
  260. if (LsaHandle){
  261. LsaClose( LsaHandle );
  262. }
  263. return(RtlNtStatusToDosError(NtStatus));
  264. }
  265. DWORD
  266. SvcapisDoPrintSharesExist(
  267. IN PWSTR pszMachineName,
  268. OUT BOOL *pbPrintSharesExist
  269. )
  270. /*++
  271. Routine Description:
  272. Detects if print shares exist on machine
  273. Arguments:
  274. pszMachineName - name of machine to evaluate function on
  275. pbPrintSharesExist - pointer to boolean to fill
  276. Return:
  277. Win32/NetApi error code
  278. --*/
  279. {
  280. NET_API_STATUS NetStatus;
  281. DWORD ParmError = 0;
  282. DWORD Status = ERROR_SUCCESS;
  283. LPBYTE Buffer = NULL;
  284. DWORD EntriesRead = 0;
  285. DWORD TotalEntries = 0;
  286. LPSHARE_INFO_1 pShareInfo = NULL;
  287. if (pbPrintSharesExist == NULL) {
  288. return ERROR_INVALID_PARAMETER;
  289. }
  290. *pbPrintSharesExist = FALSE;
  291. NetStatus = NetShareEnum(
  292. pszMachineName,
  293. 1,
  294. &Buffer,
  295. MAX_PREFERRED_LENGTH,
  296. &EntriesRead,
  297. &TotalEntries,
  298. NULL
  299. );
  300. if (NetStatus != NERR_Success ||
  301. EntriesRead == 0 ||
  302. Buffer == NULL)
  303. {
  304. goto ExitHandler;
  305. }
  306. pShareInfo = (LPSHARE_INFO_1)Buffer;
  307. for (ULONG uIndex=0; uIndex < EntriesRead; uIndex++) {
  308. if (pShareInfo[uIndex].shi1_type == STYPE_PRINTQ){
  309. *pbPrintSharesExist = TRUE;
  310. break;
  311. }
  312. }
  313. ExitHandler:
  314. if (Buffer) {
  315. NetApiBufferFree(Buffer);
  316. }
  317. return NetStatus;
  318. }
  319. DWORD
  320. SvcapisIsRemoteAssistanceEnabled(
  321. IN PWSTR pszMachineName,
  322. OUT BOOL *pbIsRemoteAssistanceEnabled
  323. )
  324. /*++
  325. Routine Description:
  326. Detects if remote assistance is enabled on machine
  327. Arguments:
  328. pszMachineName - name of machine to evaluate function on
  329. pbIsRemoteAssistanceEnabled - pointer to boolean to fill
  330. Return:
  331. Win32 error code
  332. --*/
  333. {
  334. DWORD rc = ERROR_SUCCESS;
  335. OSVERSIONINFOEX osVersionInfo;
  336. if (pbIsRemoteAssistanceEnabled == NULL) {
  337. return ERROR_INVALID_PARAMETER;
  338. }
  339. if (!GetVersionEx((LPOSVERSIONINFOW)&osVersionInfo)) {
  340. rc = GetLastError();
  341. return E_INVALIDARG;
  342. }
  343. if (osVersionInfo.dwMajorVersion == 5 &&
  344. osVersionInfo.dwMajorVersion < 1) {
  345. //
  346. // remote assistance available on > w2k
  347. //
  348. return S_OK;
  349. }
  350. HRESULT hr = S_OK;
  351. CComPtr <IWbemLocator> pWbemLocator = NULL;
  352. CComPtr <IWbemServices> pWbemServices = NULL;
  353. CComPtr <IWbemClassObject> pWbemTsObjectInstance = NULL;
  354. CComPtr <IEnumWbemClassObject> pWbemEnumObject = NULL;
  355. CComBSTR bstrMachineAndNamespace;
  356. ULONG nReturned = 0;
  357. bstrMachineAndNamespace = pszMachineName;
  358. bstrMachineAndNamespace += L"\\root\\cimv2";
  359. hr = CoCreateInstance(
  360. CLSID_WbemLocator,
  361. 0,
  362. CLSCTX_INPROC_SERVER,
  363. IID_IWbemLocator,
  364. (LPVOID *) &pWbemLocator
  365. );
  366. if (FAILED(hr) || pWbemLocator == NULL ) {
  367. goto ExitHandler;
  368. }
  369. hr = pWbemLocator->ConnectServer(
  370. bstrMachineAndNamespace,
  371. NULL,
  372. NULL,
  373. NULL,
  374. 0L,
  375. NULL,
  376. NULL,
  377. &pWbemServices
  378. );
  379. if (FAILED(hr) || pWbemServices == NULL ) {
  380. goto ExitHandler;
  381. }
  382. hr = CoSetProxyBlanket(
  383. pWbemServices,
  384. RPC_C_AUTHN_WINNT,
  385. RPC_C_AUTHZ_NONE,
  386. NULL,
  387. RPC_C_AUTHN_LEVEL_PKT,
  388. RPC_C_IMP_LEVEL_IMPERSONATE,
  389. NULL,
  390. EOAC_NONE
  391. );
  392. if (FAILED(hr)) {
  393. goto ExitHandler;
  394. }
  395. hr = pWbemServices->ExecQuery(CComBSTR(L"WQL"),
  396. CComBSTR(L"SELECT * FROM Win32_TerminalServiceSetting"),
  397. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  398. NULL,
  399. &pWbemEnumObject);
  400. if (FAILED(hr) || pWbemEnumObject == NULL) {
  401. goto ExitHandler;
  402. }
  403. hr = pWbemEnumObject->Next(WBEM_INFINITE, 1, &pWbemTsObjectInstance, &nReturned);
  404. if (FAILED(hr) || pWbemTsObjectInstance == NULL) {
  405. goto ExitHandler;
  406. }
  407. VARIANT vHelp;
  408. VariantInit(&vHelp);
  409. hr = pWbemTsObjectInstance->Get(CComBSTR(L"Help"),
  410. 0,
  411. &vHelp,
  412. NULL,
  413. NULL);
  414. if (FAILED(hr)) {
  415. goto ExitHandler;
  416. }
  417. if (V_VT(&vHelp) == VT_NULL) {
  418. goto ExitHandler;
  419. }
  420. ULONG uHelp = V_INT(&vHelp);
  421. if (uHelp) {
  422. *pbIsRemoteAssistanceEnabled = TRUE;
  423. }
  424. ExitHandler:
  425. if (V_VT(&vHelp) != VT_NULL) {
  426. VariantClear( &vHelp );
  427. }
  428. return hr;
  429. }
  430. DWORD
  431. SvcapisIsWINSClient(
  432. IN PWSTR pszMachineName,
  433. OUT BOOL *pbIsWINSClient
  434. )
  435. /*++
  436. Routine Description:
  437. Detects if machine is a WINS client
  438. Arguments:
  439. pszMachineName - name of machine to evaluate function on (this API is not remotable)
  440. pbIsWINSClient - pointer to boolean to fill
  441. Return:
  442. Win32 error code
  443. --*/
  444. {
  445. ULONG ulSize = 0;
  446. DWORD rc = ERROR_SUCCESS;
  447. PIP_ADAPTER_INFO pAdapterInfo = NULL;
  448. if (pbIsWINSClient == NULL) {
  449. return ERROR_INVALID_PARAMETER;
  450. }
  451. if (pszMachineName != NULL) {
  452. return ERROR_CALL_NOT_IMPLEMENTED;
  453. }
  454. *pbIsWINSClient = FALSE;
  455. rc = GetAdaptersInfo(
  456. NULL,
  457. &ulSize);
  458. if (rc != ERROR_BUFFER_OVERFLOW &&
  459. rc != ERROR_INSUFFICIENT_BUFFER ){
  460. goto ExitHandler;
  461. }
  462. pAdapterInfo = (PIP_ADAPTER_INFO) LocalAlloc(LMEM_ZEROINIT, ulSize);
  463. if (pAdapterInfo == NULL) {
  464. rc = ERROR_NOT_ENOUGH_MEMORY;
  465. goto ExitHandler;
  466. }
  467. rc = GetAdaptersInfo(
  468. pAdapterInfo,
  469. &ulSize);
  470. if (rc != ERROR_SUCCESS){
  471. goto ExitHandler;
  472. }
  473. for(PIP_ADAPTER_INFO pCurrAdapterInfo=pAdapterInfo;
  474. pCurrAdapterInfo!=NULL;
  475. pCurrAdapterInfo=pCurrAdapterInfo->Next){
  476. if (pCurrAdapterInfo->PrimaryWinsServer.IpAddress.String != NULL ||
  477. pCurrAdapterInfo->SecondaryWinsServer.IpAddress.String != NULL ){
  478. *pbIsWINSClient = TRUE;
  479. break;
  480. }
  481. }
  482. ExitHandler:
  483. if (pAdapterInfo) {
  484. LocalFree(pAdapterInfo);
  485. }
  486. return rc;
  487. }
  488. DWORD
  489. SvcapisAreTasksScheduled(
  490. IN PWSTR pszMachineName,
  491. OUT BOOL *pbAreTasksScheduled
  492. )
  493. /*++
  494. Routine Description:
  495. Detects if at least one task is scheduled
  496. Arguments:
  497. pszMachineName - name of machine to evaluate function on
  498. pbAreTasksScheduled - pointer to boolean to fill
  499. Return:
  500. Win32 error code
  501. --*/
  502. {
  503. HRESULT hr = S_OK;
  504. CComPtr <ITaskScheduler> pITS = NULL;
  505. CComPtr <IEnumWorkItems> pIEnum = NULL;
  506. if (pbAreTasksScheduled == NULL) {
  507. return ERROR_INVALID_PARAMETER;
  508. }
  509. *pbAreTasksScheduled = FALSE;
  510. hr = CoInitialize(NULL);
  511. if (FAILED(hr)){
  512. return hr;
  513. }
  514. hr = CoCreateInstance(CLSID_CTaskScheduler,
  515. NULL,
  516. CLSCTX_INPROC_SERVER,
  517. IID_ITaskScheduler,
  518. (void **) &pITS);
  519. if (FAILED(hr) || pITS == NULL ){
  520. goto ExitHandler;
  521. }
  522. if (pszMachineName != NULL) {
  523. hr = pITS->SetTargetComputer((LPCTSTR)pszMachineName);
  524. if (SCHED_E_SERVICE_NOT_INSTALLED == hr) {
  525. hr = S_OK;
  526. goto ExitHandler;
  527. }
  528. if (FAILED(hr)) {
  529. goto ExitHandler;
  530. }
  531. }
  532. hr = pITS->Enum(&pIEnum);
  533. if (FAILED(hr) || pIEnum == NULL){
  534. goto ExitHandler;
  535. }
  536. LPWSTR *lpwszNames = NULL;
  537. DWORD dwFetchedTasks = 0;
  538. hr = pIEnum->Next(1,
  539. &lpwszNames,
  540. &dwFetchedTasks);
  541. if (S_FALSE == hr){
  542. hr = ERROR_SUCCESS;
  543. }
  544. if (FAILED(hr)){
  545. goto ExitHandler;
  546. }
  547. if (dwFetchedTasks > 0 ){
  548. *pbAreTasksScheduled = TRUE;
  549. }
  550. ExitHandler:
  551. if (lpwszNames){
  552. CoTaskMemFree(lpwszNames);
  553. }
  554. CoUninitialize();
  555. return hr;
  556. }
  557. DWORD
  558. SvcapisUPSAttached(
  559. IN PWSTR pszMachineName,
  560. OUT BOOL *pbIsUPSAttached
  561. )
  562. /*++
  563. Routine Description:
  564. Detects if UPS hardware is(was) attached
  565. Arguments:
  566. pszMachineName - name of machine to evaluate function on
  567. pbIsUPSAttached - pointer to boolean to fill
  568. Return:
  569. Win32 error code
  570. --*/
  571. {
  572. DWORD rc = ERROR_SUCCESS;
  573. HKEY hKeyHklm = HKEY_LOCAL_MACHINE;
  574. HKEY hKey = NULL;
  575. DWORD RegType;
  576. DWORD cbData;
  577. DWORD dwOptions = 0;
  578. if (pbIsUPSAttached == NULL) {
  579. return ERROR_INVALID_PARAMETER;
  580. }
  581. *pbIsUPSAttached = FALSE;
  582. if (pszMachineName) {
  583. rc = RegConnectRegistry(
  584. pszMachineName,
  585. HKEY_LOCAL_MACHINE,
  586. &hKeyHklm
  587. );
  588. }
  589. if (rc != ERROR_SUCCESS) {
  590. goto ExitHandler;
  591. }
  592. rc = RegOpenKeyEx(hKeyHklm,
  593. L"SYSTEM\\CurrentControlSet\\Services\\UPS",
  594. 0,
  595. KEY_READ | KEY_QUERY_VALUE,
  596. &hKey
  597. );
  598. if (rc != ERROR_SUCCESS) {
  599. goto ExitHandler;
  600. }
  601. cbData = sizeof(DWORD);
  602. rc = RegQueryValueEx (
  603. hKey,
  604. L"Options",
  605. NULL,
  606. &RegType,
  607. (LPBYTE)&dwOptions,
  608. &cbData
  609. );
  610. if (rc != ERROR_SUCCESS) {
  611. goto ExitHandler;
  612. }
  613. if (dwOptions & 0x1) {
  614. *pbIsUPSAttached = TRUE;
  615. }
  616. ExitHandler:
  617. if (hKeyHklm != HKEY_LOCAL_MACHINE) {
  618. RegCloseKey(hKeyHklm);
  619. }
  620. if (hKey) {
  621. RegCloseKey(hKey);
  622. }
  623. if (rc == ERROR_FILE_NOT_FOUND ||
  624. rc == ERROR_PATH_NOT_FOUND) {
  625. rc = ERROR_SUCCESS;
  626. }
  627. return rc;
  628. }
  629. DWORD
  630. SvcapisAutoUpdateEnabled(
  631. IN PWSTR pszMachineName,
  632. OUT BOOL *pbAutoUpdateIsEnabled
  633. )
  634. /*++
  635. Routine Description:
  636. Detects if Auto Update is enabled
  637. Arguments:
  638. pszMachineName - name of machine to evaluate function on
  639. pbAutoUpdateIsEnabled - pointer to boolean to fill
  640. Return:
  641. Win32 error code
  642. --*/
  643. {
  644. DWORD rc = ERROR_SUCCESS;
  645. HKEY hKeyHklm = HKEY_LOCAL_MACHINE;
  646. HKEY hKey = NULL;
  647. DWORD RegType;
  648. DWORD cbData;
  649. DWORD dwOptions = 0;
  650. if (pbAutoUpdateIsEnabled == NULL) {
  651. return ERROR_INVALID_PARAMETER;
  652. }
  653. *pbAutoUpdateIsEnabled = FALSE;
  654. if (pszMachineName) {
  655. rc = RegConnectRegistry(
  656. pszMachineName,
  657. HKEY_LOCAL_MACHINE,
  658. &hKeyHklm
  659. );
  660. }
  661. if (rc != ERROR_SUCCESS) {
  662. goto ExitHandler;
  663. }
  664. rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  665. L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update",
  666. 0,
  667. KEY_READ | KEY_QUERY_VALUE,
  668. &hKey
  669. );
  670. if (rc != ERROR_SUCCESS) {
  671. goto ExitHandler;
  672. }
  673. cbData = sizeof(DWORD);
  674. rc = RegQueryValueEx (
  675. hKey,
  676. L"AUOptions",
  677. NULL,
  678. &RegType,
  679. (LPBYTE)&dwOptions,
  680. &cbData
  681. );
  682. if (rc != ERROR_SUCCESS) {
  683. goto ExitHandler;
  684. }
  685. if (!(dwOptions & 1)) {
  686. *pbAutoUpdateIsEnabled = TRUE;
  687. }
  688. ExitHandler:
  689. if (hKeyHklm != HKEY_LOCAL_MACHINE) {
  690. RegCloseKey(hKeyHklm);
  691. }
  692. if (hKey) {
  693. RegCloseKey(hKey);
  694. }
  695. if (rc == ERROR_FILE_NOT_FOUND ||
  696. rc == ERROR_PATH_NOT_FOUND) {
  697. rc = ERROR_SUCCESS;
  698. }
  699. return rc;
  700. }
  701. DWORD
  702. ServicesFoundThatAreNotinKB(
  703. OUT BOOL *pbIsServiceSatisfiable
  704. )
  705. /*++
  706. Routine Description:
  707. Detects if service is enabled on machine
  708. Arguments:
  709. pbIsServiceSatisfiable - pointer to boolean to fill
  710. Return:
  711. Win32 error code
  712. --*/
  713. {
  714. if (pbIsServiceSatisfiable == NULL) {
  715. return ERROR_INVALID_PARAMETER;
  716. }
  717. *pbIsServiceSatisfiable = TRUE;
  718. return ERROR_SUCCESS;
  719. }
  720. DWORD
  721. SvcapisIsPerfCollectionScheduled(
  722. IN PWSTR pszMachineName,
  723. OUT BOOL *pbIsPerfCollectionScheduled
  724. )
  725. /*++
  726. Routine Description:
  727. Detects if perf data is being collected on the machine
  728. Arguments:
  729. pszMachineName - name of machine to evaluate function on
  730. pbIsPerfCollectionScheduled - pointer to boolean to fill
  731. Return:
  732. Win32 error code
  733. --*/
  734. {
  735. BYTE byStartupType;
  736. DWORD rc;
  737. if (pbIsPerfCollectionScheduled == NULL) {
  738. return ERROR_INVALID_PARAMETER;
  739. }
  740. *pbIsPerfCollectionScheduled = FALSE;
  741. rc = SvcapispQueryServiceStartupType(pszMachineName,
  742. L"SysmonLog",
  743. &byStartupType
  744. );
  745. if (rc != ERROR_SUCCESS) {
  746. goto ExitHandler;
  747. }
  748. *pbIsPerfCollectionScheduled = (byStartupType == SERVICE_AUTO_START ? TRUE : FALSE);
  749. ExitHandler:
  750. return rc;
  751. }
  752. DWORD
  753. SvcapisIsSBS(
  754. IN PWSTR pszMachineName,
  755. OUT BOOL *pbIsSmallBusinessServer
  756. )
  757. /*++
  758. Routine Description:
  759. Routine called to check if SBS is installed
  760. Arguments:
  761. pszMachineName - name of machine to evaluate function on
  762. pbIsSmallBusinessServer - booolean to fill
  763. Return:
  764. Win32 error code
  765. ++*/
  766. {
  767. if (pbIsSmallBusinessServer == NULL) {
  768. return ERROR_INVALID_PARAMETER;
  769. }
  770. *pbIsSmallBusinessServer = FALSE;
  771. DWORD rc = ERROR_SUCCESS;
  772. HRESULT hr = S_OK;
  773. OSVERSIONINFOEX osVersionInfo;
  774. osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
  775. if (NULL == pszMachineName) {
  776. if (!GetVersionEx((LPOSVERSIONINFOW)&osVersionInfo)) {
  777. rc = GetLastError();
  778. goto ExitHandler;
  779. }
  780. }
  781. else {
  782. hr = SvcapispGetRemoteOSVersionInfo(
  783. pszMachineName,
  784. &osVersionInfo);
  785. if (FAILED(hr)) {
  786. rc = ERROR_PRODUCT_VERSION;
  787. goto ExitHandler;
  788. }
  789. }
  790. if (osVersionInfo.dwMajorVersion == VER_SUITE_SMALLBUSINESS ||
  791. osVersionInfo.dwMajorVersion == VER_SUITE_SMALLBUSINESS_RESTRICTED) {
  792. *pbIsSmallBusinessServer = TRUE;
  793. }
  794. ExitHandler:
  795. return rc;
  796. }
  797. DWORD
  798. SvcapisIsDC(
  799. IN PWSTR pszMachineName,
  800. OUT BOOL *pbIsDC
  801. )
  802. /*++
  803. Routine Description:
  804. Detects if machine is a DC
  805. Arguments:
  806. pszMachineName - name of machine to evaluate function on
  807. pbIsDC - pointer to boolean to fill
  808. Return:
  809. Win32 error code
  810. --*/
  811. {
  812. DWORD rc = ERROR_SUCCESS;
  813. if (pbIsDC == NULL) {
  814. return ERROR_INVALID_PARAMETER;
  815. }
  816. *pbIsDC = FALSE;
  817. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole=NULL;
  818. HINSTANCE hDsRoleDll = LoadLibrary(TEXT("netapi32.dll"));
  819. if ( hDsRoleDll == NULL) {
  820. rc = ERROR_MOD_NOT_FOUND;
  821. goto ExitHandler;
  822. }
  823. PVOID pfDsRole;
  824. pfDsRole = (PVOID)GetProcAddress(
  825. hDsRoleDll,
  826. "DsRoleGetPrimaryDomainInformation");
  827. if ( pfDsRole == NULL ){
  828. rc = ERROR_PROC_NOT_FOUND;
  829. goto ExitHandler;
  830. }
  831. rc = (*((PFGETDOMAININFO)pfDsRole))(
  832. pszMachineName,
  833. DsRolePrimaryDomainInfoBasic,
  834. (PBYTE *)&pDsRole
  835. );
  836. if (rc != ERROR_SUCCESS || NULL == pDsRole) {
  837. goto ExitHandler;
  838. }
  839. if ( pDsRole->MachineRole == DsRole_RolePrimaryDomainController ||
  840. pDsRole->MachineRole == DsRole_RoleBackupDomainController ) {
  841. *pbIsDC = TRUE;
  842. }
  843. pfDsRole = (PVOID)GetProcAddress(
  844. hDsRoleDll,
  845. "DsRoleFreeMemory");
  846. if ( pfDsRole ) {
  847. (*((PFDSFREE)pfDsRole))( pDsRole );
  848. }
  849. ExitHandler:
  850. if (hDsRoleDll) {
  851. FreeLibrary(hDsRoleDll);
  852. }
  853. return(rc);
  854. }
  855. DWORD
  856. SvcapisIsAppModeTS(
  857. IN PWSTR pszMachineName,
  858. OUT BOOL *pbIsAppModeTS
  859. )
  860. /*++
  861. Routine Description:
  862. Detects if TS is in app mode
  863. Arguments:
  864. pszMachineName - name of machine to evaluate function on
  865. pbIsAppModeTS - pointer to boolean to fill
  866. Return:
  867. Win32 error code
  868. --*/
  869. {
  870. DWORD rc = ERROR_SUCCESS;
  871. HKEY hKeyHklm = HKEY_LOCAL_MACHINE;
  872. HKEY hKey = NULL;
  873. DWORD RegType;
  874. DWORD cbData;
  875. DWORD dwOptions = 0;
  876. OSVERSIONINFOEX osVersionInfo;
  877. HRESULT hr = S_OK;
  878. if (pbIsAppModeTS == NULL) {
  879. return ERROR_INVALID_PARAMETER;
  880. }
  881. *pbIsAppModeTS = FALSE;
  882. //
  883. // SSR paradigm for preprocessing remoteability
  884. //
  885. // if local, try the traditional approach
  886. // if remote, dig-into the registry etc. (maybe less reliable)
  887. //
  888. if (pszMachineName == NULL) {
  889. //
  890. // local
  891. //
  892. if (!GetVersionEx((LPOSVERSIONINFOW)&osVersionInfo)) {
  893. rc = GetLastError();
  894. goto ExitHandler;
  895. }
  896. } else {
  897. //
  898. // remote
  899. //
  900. hr = SvcapispGetRemoteOSVersionInfo(
  901. pszMachineName,
  902. &osVersionInfo);
  903. if (FAILED(hr)) {
  904. rc = ERROR_PRODUCT_VERSION;
  905. goto ExitHandler;
  906. }
  907. }
  908. if (osVersionInfo.wSuiteMask & VER_SUITE_TERMINAL &&
  909. osVersionInfo.wSuiteMask & VER_SUITE_SINGLEUSERTS) {
  910. *pbIsAppModeTS = TRUE;
  911. }
  912. /*
  913. rc = RegConnectRegistry(
  914. pszMachineName,
  915. HKEY_LOCAL_MACHINE,
  916. &hKeyHklm
  917. );
  918. if (rc != ERROR_SUCCESS) {
  919. goto ExitHandler;
  920. }
  921. rc = RegOpenKeyEx(hKeyHklm,
  922. L"System\\CurrentControlSet\\Control\\Terminal Server",
  923. 0,
  924. KEY_READ | KEY_QUERY_VALUE,
  925. &hKey
  926. );
  927. if (rc != ERROR_SUCCESS) {
  928. goto ExitHandler;
  929. }
  930. cbData = sizeof(DWORD);
  931. rc = RegQueryValueEx (
  932. hKey,
  933. L"TSAppCompat",
  934. NULL,
  935. &RegType,
  936. (LPBYTE)&dwOptions,
  937. &cbData
  938. );
  939. if (rc != ERROR_SUCCESS) {
  940. goto ExitHandler;
  941. }
  942. if (dwOptions & 0x1) {
  943. *pbIsAppModeTS = TRUE;
  944. }
  945. }
  946. */
  947. ExitHandler:
  948. if (hKeyHklm != HKEY_LOCAL_MACHINE) {
  949. RegCloseKey(hKeyHklm);
  950. }
  951. if (hKey) {
  952. RegCloseKey(hKey);
  953. }
  954. if (rc == ERROR_FILE_NOT_FOUND ||
  955. rc == ERROR_PATH_NOT_FOUND) {
  956. rc = ERROR_SUCCESS;
  957. }
  958. return rc;
  959. }
  960. DWORD
  961. SvcapisDFSSharesExist(
  962. IN PWSTR pszMachineName,
  963. OUT BOOL *pbDFSSharesExist
  964. )
  965. /*++
  966. Routine Description:
  967. Detects if DFS shares exist on machine
  968. Arguments:
  969. pszMachineName - name of machine to evaluate function on
  970. pbDFSSharesExist - pointer to boolean to fill
  971. Return:
  972. Win32/NetApi error code
  973. --*/
  974. {
  975. NET_API_STATUS NetStatus;
  976. DWORD ParmError = 0;
  977. DWORD Status = ERROR_SUCCESS;
  978. LPBYTE Buffer = NULL;
  979. DWORD EntriesRead = 0;
  980. DWORD TotalEntries = 0;
  981. LPSHARE_INFO_1 pShareInfo = NULL;
  982. if (pbDFSSharesExist == NULL) {
  983. return ERROR_INVALID_PARAMETER;
  984. }
  985. *pbDFSSharesExist = FALSE;
  986. NetStatus = NetShareEnum(
  987. pszMachineName,
  988. 1,
  989. &Buffer,
  990. MAX_PREFERRED_LENGTH,
  991. &EntriesRead,
  992. &TotalEntries,
  993. NULL
  994. );
  995. if (NetStatus != NERR_Success ||
  996. EntriesRead == 0 ||
  997. Buffer == NULL) {
  998. goto ExitHandler;
  999. }
  1000. pShareInfo = (LPSHARE_INFO_1)Buffer;
  1001. PSHARE_INFO_1005 pBufShareInfo = NULL;
  1002. DWORD shi1005_flags;
  1003. for (ULONG uIndex=0; uIndex < EntriesRead; uIndex++) {
  1004. if (pShareInfo[uIndex].shi1_type == STYPE_DISKTREE) {
  1005. NetStatus = NetShareGetInfo(
  1006. pszMachineName,
  1007. pShareInfo[uIndex].shi1_netname,
  1008. 1005,
  1009. (LPBYTE *) &pBufShareInfo
  1010. );
  1011. if (NetStatus != NERR_Success ||
  1012. pBufShareInfo == NULL) {
  1013. goto ExitHandler;
  1014. }
  1015. shi1005_flags = pBufShareInfo->shi1005_flags;
  1016. NetApiBufferFree(pBufShareInfo);
  1017. pBufShareInfo = NULL;
  1018. if (SHI1005_FLAGS_DFS & shi1005_flags) {
  1019. *pbDFSSharesExist = TRUE;
  1020. break;
  1021. }
  1022. }
  1023. }
  1024. ExitHandler:
  1025. if (Buffer) {
  1026. NetApiBufferFree(Buffer);
  1027. }
  1028. return NetStatus;
  1029. }
  1030. DWORD
  1031. SvcapisIsUsingDHCP(
  1032. IN PWSTR pszMachineName,
  1033. OUT BOOL *pbIsUsingDHCP
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. Detects if any adapter on this machine is using DHCP
  1038. in its TCP/IP stack
  1039. Arguments:
  1040. pszMachineName - name of machine to evaluate function on
  1041. pbIsUsingDHCP - pointer to boolean to fill
  1042. Return:
  1043. Win32 error code
  1044. --*/
  1045. {
  1046. DWORD rc = ERROR_SUCCESS;
  1047. DWORD dwOutBufLen = 0;
  1048. PIP_ADAPTER_ADDRESSES pAdapterAddresses = NULL;
  1049. if (pbIsUsingDHCP == NULL) {
  1050. return ERROR_INVALID_PARAMETER;
  1051. }
  1052. *pbIsUsingDHCP = FALSE;
  1053. rc = GetAdaptersAddresses(
  1054. AF_UNSPEC,
  1055. 0,
  1056. NULL,
  1057. NULL,
  1058. &dwOutBufLen
  1059. );
  1060. if (ERROR_SUCCESS == rc ||
  1061. (ERROR_SUCCESS != rc && ERROR_BUFFER_OVERFLOW != rc)) {
  1062. goto ExitHandler;
  1063. }
  1064. pAdapterAddresses = (PIP_ADAPTER_ADDRESSES) LocalAlloc(LMEM_ZEROINIT, dwOutBufLen);
  1065. if ( NULL == pAdapterAddresses) {
  1066. rc = ERROR_NOT_ENOUGH_MEMORY;
  1067. goto ExitHandler;
  1068. }
  1069. rc = GetAdaptersAddresses(
  1070. AF_UNSPEC,
  1071. 0,
  1072. NULL,
  1073. pAdapterAddresses,
  1074. &dwOutBufLen
  1075. );
  1076. if (ERROR_SUCCESS != rc) {
  1077. goto ExitHandler;
  1078. }
  1079. for (PIP_ADAPTER_ADDRESSES pCurrentAddress = pAdapterAddresses;
  1080. pCurrentAddress != NULL;
  1081. pCurrentAddress = pCurrentAddress->Next) {
  1082. if (pCurrentAddress->Flags & IP_ADAPTER_DHCP_ENABLED) {
  1083. *pbIsUsingDHCP = TRUE;
  1084. goto ExitHandler;
  1085. }
  1086. }
  1087. ExitHandler:
  1088. if (pAdapterAddresses) {
  1089. LocalFree(pAdapterAddresses);
  1090. }
  1091. return(rc);
  1092. }
  1093. DWORD
  1094. SvcapisIsUsingDDNS(
  1095. IN PWSTR pszMachineName,
  1096. OUT BOOL *pbIsUsingDDNS
  1097. )
  1098. /*++
  1099. Routine Description:
  1100. Detects if any adapter on this machine is using DDNS (DNS is always enabled)
  1101. in its TCP/IP stack
  1102. Arguments:
  1103. pszMachineName - name of machine to evaluate function on
  1104. pbIsUsingDHCP - pointer to boolean to fill
  1105. Return:
  1106. Win32 error code
  1107. --*/
  1108. {
  1109. DWORD rc = ERROR_SUCCESS;
  1110. DWORD dwOutBufLen = 0;
  1111. PIP_ADAPTER_ADDRESSES pAdapterAddresses;
  1112. if (pbIsUsingDDNS == NULL) {
  1113. return ERROR_INVALID_PARAMETER;
  1114. }
  1115. *pbIsUsingDDNS = FALSE;
  1116. rc = GetAdaptersAddresses(
  1117. AF_UNSPEC,
  1118. 0,
  1119. NULL,
  1120. NULL,
  1121. &dwOutBufLen
  1122. );
  1123. if (ERROR_SUCCESS == rc ||
  1124. (ERROR_SUCCESS != rc && ERROR_BUFFER_OVERFLOW != rc)) {
  1125. goto ExitHandler;
  1126. }
  1127. pAdapterAddresses = (PIP_ADAPTER_ADDRESSES) LocalAlloc(LMEM_ZEROINIT, dwOutBufLen);
  1128. if ( NULL == pAdapterAddresses) {
  1129. goto ExitHandler;
  1130. }
  1131. rc = GetAdaptersAddresses(
  1132. AF_UNSPEC,
  1133. 0,
  1134. NULL,
  1135. pAdapterAddresses,
  1136. &dwOutBufLen
  1137. );
  1138. if (ERROR_SUCCESS != rc) {
  1139. goto ExitHandler;
  1140. }
  1141. for (PIP_ADAPTER_ADDRESSES pCurrentAddress = pAdapterAddresses;
  1142. pCurrentAddress != NULL;
  1143. pCurrentAddress = pCurrentAddress->Next) {
  1144. if (pCurrentAddress->Flags & IP_ADAPTER_DDNS_ENABLED) {
  1145. *pbIsUsingDDNS = TRUE;
  1146. goto ExitHandler;
  1147. }
  1148. }
  1149. ExitHandler:
  1150. if (pAdapterAddresses) {
  1151. LocalFree(pAdapterAddresses);
  1152. }
  1153. return(rc);
  1154. }
  1155. HRESULT
  1156. SvcapispGetRemoteOSVersionInfo(
  1157. IN PWSTR pszMachineName,
  1158. OUT OSVERSIONINFOEX *posVersionInfo
  1159. )
  1160. /*++
  1161. Routine Description:
  1162. Routine called to get version info from remote machine via WMI
  1163. Arguments:
  1164. pszMachineName - remote machine name
  1165. posVersionInfo - os version info to fill via WMI queries
  1166. Return:
  1167. HRESULT error code
  1168. ++*/
  1169. {
  1170. HRESULT hr = S_OK;
  1171. CComPtr <IWbemLocator> pWbemLocator = NULL;
  1172. CComPtr <IWbemServices> pWbemServices = NULL;
  1173. CComPtr <IWbemClassObject> pWbemOsObjectInstance = NULL;
  1174. CComPtr <IEnumWbemClassObject> pWbemEnumObject = NULL;
  1175. CComBSTR bstrMachineAndNamespace;
  1176. ULONG nReturned = 0;
  1177. bstrMachineAndNamespace = pszMachineName;
  1178. bstrMachineAndNamespace += L"\\root\\cimv2";
  1179. hr = CoCreateInstance(
  1180. CLSID_WbemLocator,
  1181. 0,
  1182. CLSCTX_INPROC_SERVER,
  1183. IID_IWbemLocator,
  1184. (LPVOID *) &pWbemLocator
  1185. );
  1186. if (FAILED(hr) || pWbemLocator == NULL ) {
  1187. goto ExitHandler;
  1188. }
  1189. hr = pWbemLocator->ConnectServer(
  1190. bstrMachineAndNamespace,
  1191. NULL,
  1192. NULL,
  1193. NULL,
  1194. 0L,
  1195. NULL,
  1196. NULL,
  1197. &pWbemServices
  1198. );
  1199. if (FAILED(hr) || pWbemServices == NULL ) {
  1200. goto ExitHandler;
  1201. }
  1202. hr = CoSetProxyBlanket(
  1203. pWbemServices,
  1204. RPC_C_AUTHN_WINNT,
  1205. RPC_C_AUTHZ_NONE,
  1206. NULL,
  1207. RPC_C_AUTHN_LEVEL_PKT,
  1208. RPC_C_IMP_LEVEL_IMPERSONATE,
  1209. NULL,
  1210. EOAC_NONE
  1211. );
  1212. if (FAILED(hr)) {
  1213. goto ExitHandler;
  1214. }
  1215. hr = pWbemServices->ExecQuery(CComBSTR(L"WQL"),
  1216. CComBSTR(L"SELECT * FROM Win32_OperatingSystem"),
  1217. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  1218. NULL,
  1219. &pWbemEnumObject);
  1220. if (FAILED(hr) || pWbemEnumObject == NULL) {
  1221. goto ExitHandler;
  1222. }
  1223. hr = pWbemEnumObject->Next(WBEM_INFINITE, 1, &pWbemOsObjectInstance, &nReturned);
  1224. if (FAILED(hr) || pWbemOsObjectInstance == NULL) {
  1225. goto ExitHandler;
  1226. }
  1227. VARIANT vVersion;
  1228. VariantInit(&vVersion);
  1229. hr = pWbemOsObjectInstance->Get(CComBSTR(L"Version"),
  1230. 0,
  1231. &vVersion,
  1232. NULL,
  1233. NULL);
  1234. if (FAILED(hr)) {
  1235. goto ExitHandler;
  1236. }
  1237. if (V_VT(&vVersion) == VT_NULL) {
  1238. goto ExitHandler;
  1239. }
  1240. //
  1241. // extract the version information into DWORDs since
  1242. // the return type of this property is BSTR variant
  1243. // of the form "5.1.2195"
  1244. //
  1245. BSTR bstrVersion = V_BSTR(&vVersion);
  1246. WCHAR szVersion[5];
  1247. szVersion[0] = L'\0';
  1248. PWSTR pszDot = wcsstr(bstrVersion, L".");
  1249. if (NULL == pszDot) {
  1250. hr = E_INVALIDARG;
  1251. goto ExitHandler;
  1252. }
  1253. wcsncpy(szVersion, bstrVersion, 1);
  1254. posVersionInfo->dwMajorVersion = (DWORD)_wtoi(szVersion);
  1255. wcsncpy(szVersion, pszDot+1, 1);
  1256. posVersionInfo->dwMinorVersion = (DWORD)_wtoi(szVersion);
  1257. ExitHandler:
  1258. if (V_VT(&vVersion) != VT_NULL) {
  1259. VariantClear( &vVersion );
  1260. }
  1261. return hr;
  1262. }