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.

1482 lines
43 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. CONNECTWMI.cpp
  5. Abstract:
  6. Contains functions to connect to wmi.
  7. Author:
  8. Vasundhara .G
  9. Revision History:
  10. Vasundhara .G 26-sep-2k : Created It.
  11. --*/
  12. // Include files
  13. #include "pch.h"
  14. #include "getmac.h"
  15. #include "resource.h"
  16. // messages
  17. #define INPUT_PASSWORD GetResString( IDS_STR_INPUT_PASSWORD )
  18. // error constants
  19. #define E_SERVER_NOTFOUND 0x800706ba
  20. // function prototypes
  21. BOOL
  22. IsValidUserEx(
  23. IN LPCWSTR pwszUser
  24. );
  25. HRESULT
  26. GetSecurityArguments(
  27. IN IUnknown *pInterface,
  28. OUT DWORD& dwAuthorization,
  29. OUT DWORD& dwAuthentication
  30. );
  31. HRESULT
  32. SetInterfaceSecurity(
  33. IN IUnknown *pInterface,
  34. IN LPCWSTR pwszUser,
  35. IN LPCWSTR pwszPassword,
  36. OUT COAUTHIDENTITY **ppAuthIdentity
  37. );
  38. HRESULT
  39. WINAPI SetProxyBlanket(
  40. IN IUnknown *pInterface,
  41. IN DWORD dwAuthnSvc,
  42. IN DWORD dwAuthzSvc,
  43. IN LPWSTR pwszPrincipal,
  44. IN DWORD dwAuthLevel,
  45. IN DWORD dwImpLevel,
  46. IN RPC_AUTH_IDENTITY_HANDLE pAuthInfo,
  47. IN DWORD dwCapabilities
  48. );
  49. HRESULT
  50. WINAPI WbemAllocAuthIdentity(
  51. IN LPCWSTR pwszUser,
  52. IN LPCWSTR pwszPassword,
  53. IN LPCWSTR pwszDomain,
  54. OUT COAUTHIDENTITY **ppAuthIdent
  55. );
  56. BOOL
  57. PropertyGet(
  58. IN IWbemClassObject *pWmiObject,
  59. IN LPCWSTR pwszProperty,
  60. OUT CHString& strValue,
  61. IN LPCWSTR pwszDefault = V_NOT_AVAILABLE
  62. );
  63. BOOL
  64. PropertyGet(
  65. IN IWbemClassObject* pWmiObject,
  66. IN LPCWSTR pwszProperty,
  67. OUT CHString& strValue,
  68. IN LPCWSTR pwszDefault
  69. );
  70. HRESULT
  71. PropertyGet(
  72. IN IWbemClassObject* pWmiObject,
  73. IN LPCWSTR pwszProperty,
  74. OUT _variant_t& varValue
  75. );
  76. BOOL
  77. IsValidUserEx(
  78. IN LPCWSTR pwszUser
  79. )
  80. /*++
  81. Routine Description:
  82. Validates the user name.
  83. Arguments:
  84. [IN] pwszUser - Holds the user name to be validated.
  85. Return Value:
  86. returns TRUE if user name is a valid user else FALSE.
  87. --*/
  88. {
  89. // local variables
  90. CHString strUser;
  91. LONG lPos = 0;
  92. if ( ( NULL == pwszUser ) )
  93. {
  94. return TRUE;
  95. }
  96. if( 0 == StringLength( pwszUser, 0 ) )
  97. {
  98. return TRUE;
  99. }
  100. try
  101. {
  102. // get user into local memory
  103. strUser = pwszUser;
  104. // user name should not be just '\'
  105. if ( 0 == strUser.CompareNoCase( L"\\" ) )
  106. {
  107. return FALSE;
  108. }
  109. // user name should not contain invalid characters
  110. if ( -1 != strUser.FindOneOf( L"/[]:|<>+=;,?*" ) )
  111. {
  112. return FALSE;
  113. }
  114. lPos = strUser.Find( L'\\' );
  115. if ( -1 != lPos )
  116. {
  117. // '\' character exists in the user name
  118. // strip off the user info upto first '\' character
  119. // check for one more '\' in the remaining string
  120. // if it exists, invalid user
  121. strUser = strUser.Mid( lPos + 1 );
  122. lPos = strUser.Find( L'\\' );
  123. if ( -1 != lPos )
  124. {
  125. return FALSE;
  126. }
  127. }
  128. }
  129. catch( CHeap_Exception )
  130. {
  131. WMISaveError( WBEM_E_OUT_OF_MEMORY );
  132. return FALSE;
  133. }
  134. // user name is valid
  135. return TRUE;
  136. }
  137. BOOL
  138. IsValidServerEx(
  139. IN LPCWSTR pwszServer,
  140. OUT BOOL &bLocalSystem
  141. )
  142. /*++
  143. Routine Description:
  144. Checks whether the server name is a valid server name or not.
  145. Arguments:
  146. [IN] pwszServer - Server name to be validated.
  147. [OUT] bLocalSystem - Set to TRUE if server specified is local system.
  148. Return Value:
  149. TRUE if server is valid else FALSE.
  150. --*/
  151. {
  152. // local variables
  153. CHString strTemp;
  154. if( NULL == pwszServer )
  155. {
  156. return FALSE;
  157. }
  158. if( 0 == StringLength( pwszServer, 0 ) )
  159. {
  160. bLocalSystem = TRUE;
  161. return TRUE;
  162. }
  163. bLocalSystem = FALSE;
  164. try
  165. {
  166. // get a local copy
  167. strTemp = pwszServer;
  168. if( TRUE == IsNumeric( pwszServer, 10, FALSE ) )
  169. {
  170. return FALSE;
  171. }
  172. // remove the forward slashes (UNC) if exist in the begining of the server name
  173. if ( TRUE == IsUNCFormat( strTemp ) )
  174. {
  175. strTemp = strTemp.Mid( 2 );
  176. if ( 0 == strTemp.GetLength() )
  177. {
  178. return FALSE;
  179. }
  180. }
  181. if ( -1 != strTemp.FindOneOf( L"`~!@#$^&*()+=[]{}|\\<>,?/\"':;" ) )
  182. {
  183. return FALSE;
  184. }
  185. // now check if any '\' character appears in the server name. If so error
  186. if ( -1 != strTemp.Find( L'\\' ) )
  187. {
  188. return FALSE;
  189. }
  190. // now check if server name is '.' only which represent local system in WMI
  191. // else determine whether this is a local system or not
  192. if ( 0 == strTemp.CompareNoCase( L"." ) )
  193. {
  194. bLocalSystem = TRUE;
  195. }
  196. else
  197. {
  198. bLocalSystem = IsLocalSystem( strTemp );
  199. }
  200. }
  201. catch( CHeap_Exception )
  202. {
  203. WMISaveError( WBEM_E_OUT_OF_MEMORY );
  204. return FALSE;
  205. }
  206. // valid server name
  207. return TRUE;
  208. }
  209. BOOL
  210. ConnectWmi(
  211. IN IWbemLocator *pLocator,
  212. OUT IWbemServices **ppServices,
  213. IN LPCWSTR pwszServer,
  214. OUT LPCWSTR pwszUser,
  215. OUT LPCWSTR pwszPassword,
  216. OUT COAUTHIDENTITY **ppAuthIdentity,
  217. IN BOOL bCheckWithNullPwd,
  218. IN LPCWSTR pwszNamespace,
  219. OUT HRESULT *phRes,
  220. OUT BOOL *pbLocalSystem
  221. )
  222. /*++
  223. Routine Description:
  224. Connects to wmi.
  225. Arguments:
  226. [IN] pLocator - Pointer to the IWbemLocator object.
  227. [OUT] ppServics - Pointer to IWbemServices object.
  228. [IN] pwszServer - Holds the server name to connect to.
  229. [OUT] pwszUser - Holds the user name.
  230. [OUT] pwszPassword - Holds the password.
  231. [OUT] ppAuthIdentity - Pointer to authentication structure.
  232. [IN] bCheckWithNullPwd - Specifies whether to connect through null password.
  233. [IN] pwszNamespace - Specifies the namespace to connect to.
  234. [OUT] hRes - Holds the error value.
  235. [OUT] pbLocalSystem - Holds the boolean value to represent whether the server
  236. name is local or not.
  237. Return Value:
  238. TRUE if successfully connected, FALSE if not.
  239. --*/
  240. {
  241. // local variables
  242. HRESULT hRes = 0;
  243. BOOL bResult = FALSE;
  244. BOOL bLocalSystem = FALSE;
  245. _bstr_t bstrServer;
  246. _bstr_t bstrNamespace;
  247. _bstr_t bstrUser;
  248. _bstr_t bstrPassword;
  249. // clear the error
  250. SetLastError( WBEM_S_NO_ERROR );
  251. if ( NULL != pbLocalSystem )
  252. {
  253. *pbLocalSystem = FALSE;
  254. }
  255. if ( NULL != phRes )
  256. {
  257. *phRes = WBEM_S_NO_ERROR;
  258. }
  259. // check whether locator object exists or not
  260. // if not exists, return
  261. if ( ( NULL == pLocator ) ||
  262. ( NULL == ppServices ) ||
  263. ( NULL != *ppServices ) ||
  264. ( NULL == pwszNamespace ) ||
  265. ( NULL == pbLocalSystem ) )
  266. {
  267. if ( NULL != phRes )
  268. {
  269. *phRes = WBEM_E_INVALID_PARAMETER;
  270. }
  271. // return failure
  272. return FALSE;
  273. }
  274. try
  275. {
  276. // assume that connection to WMI namespace is failed
  277. bResult = FALSE;
  278. // validate the server name
  279. // NOTE: The error being raised in custom define for '0x800706ba' value
  280. // The message that will be displayed in "The RPC server is unavailable."
  281. if ( FALSE == IsValidServerEx( pwszServer, bLocalSystem ) )
  282. {
  283. _com_issue_error( E_SERVER_NOTFOUND );
  284. }
  285. // validate the user name
  286. if ( FALSE == IsValidUserEx( pwszUser ) )
  287. {
  288. _com_issue_error( ERROR_NO_SUCH_USER );
  289. }
  290. // prepare namespace
  291. bstrNamespace = pwszNamespace; // name space
  292. if ( ( NULL != pwszServer ) && ( FALSE == bLocalSystem ) )
  293. {
  294. // get the server name
  295. bstrServer = pwszServer;
  296. // prepare the namespace
  297. // NOTE: check for the UNC naming format of the server and do
  298. if ( TRUE == IsUNCFormat( pwszServer ) )
  299. {
  300. bstrNamespace = bstrServer + L"\\" + pwszNamespace;
  301. }
  302. else
  303. {
  304. bstrNamespace = L"\\\\" + bstrServer + L"\\" + pwszNamespace;
  305. }
  306. // user credentials
  307. if ( ( NULL != pwszUser ) && ( 0 != StringLength( pwszUser, 0 ) ) )
  308. {
  309. // copy the user name
  310. bstrUser = pwszUser;
  311. // if password is empty string and if we need to check with
  312. // null password, then do not set the password and try
  313. bstrPassword = pwszPassword;
  314. if ( ( TRUE == bCheckWithNullPwd ) && ( 0 == bstrPassword.length() ) )
  315. {
  316. bstrPassword = (LPWSTR) NULL;
  317. }
  318. }
  319. }
  320. // connect to the remote system's WMI
  321. // there is a twist here ...
  322. // do not trap the ConnectServer function failure into exception
  323. // instead handle that action manually
  324. // by default try the ConnectServer function as the information which we have
  325. // in our hands at this point. If the ConnectServer is failed,
  326. // check whether password variable has any contents are not ... if no contents
  327. // check with "" (empty) password ... this might pass in this situation ..
  328. // if this call is also failed ... nothing is there that we can do ... throw the exception
  329. hRes = pLocator->ConnectServer( bstrNamespace,
  330. bstrUser, bstrPassword, 0L, 0L, NULL, NULL, ppServices );
  331. if ( FAILED( hRes ) )
  332. {
  333. //
  334. // special case ...
  335. // check whether password exists or not
  336. // NOTE: do not check for 'WBEM_E_ACCESS_DENIED'
  337. // this error code says that user with the current credentials is not
  338. // having access permisions to the 'namespace'
  339. if ( E_ACCESSDENIED == hRes )
  340. {
  341. // check if we tried to connect to the system using null password
  342. // if so, then try connecting to the remote system with empty string
  343. if ( bCheckWithNullPwd == TRUE &&
  344. bstrUser.length() != 0 && bstrPassword.length() == 0 )
  345. {
  346. // now invoke with ...
  347. hRes = pLocator->ConnectServer( bstrNamespace,
  348. bstrUser, _bstr_t( L"" ), 0L, 0L, NULL, NULL, ppServices );
  349. }
  350. }
  351. else if ( WBEM_E_LOCAL_CREDENTIALS == hRes )
  352. {
  353. // credentials were passed to the local system.
  354. // So ignore the credentials and try to reconnect
  355. bLocalSystem = TRUE;
  356. bstrUser = (LPWSTR) NULL;
  357. bstrPassword = (LPWSTR) NULL;
  358. bstrNamespace = pwszNamespace; // name space
  359. hRes = pLocator->ConnectServer( bstrNamespace,
  360. NULL, NULL, 0L, 0L, NULL, NULL, ppServices );
  361. // check the result
  362. if ( SUCCEEDED( hRes ) && NULL != phRes )
  363. {
  364. // set the last error
  365. *phRes = WBEM_E_LOCAL_CREDENTIALS;
  366. }
  367. }
  368. else if ( REGDB_E_CLASSNOTREG == hRes )
  369. {
  370. SetReason( ERROR_REMOTE_INCOMPATIBLE );
  371. *phRes = REGDB_E_CLASSNOTREG;
  372. bResult = FALSE;
  373. return bResult;
  374. }
  375. // now check the result again .. if failed .. ummmm..
  376. if ( FAILED( hRes ) )
  377. {
  378. _com_issue_error( hRes );
  379. }
  380. else
  381. {
  382. bstrPassword = L"";
  383. }
  384. }
  385. // set the security at the interface level also
  386. SAFE_EXECUTE( SetInterfaceSecurity( *ppServices,
  387. bstrUser, bstrPassword, ppAuthIdentity ) );
  388. // connection to WMI is successful
  389. bResult = TRUE;
  390. // save the hr value if needed by the caller
  391. if ( NULL != phRes )
  392. {
  393. *phRes = WBEM_S_NO_ERROR;
  394. }
  395. if ( NULL != pbLocalSystem )
  396. {
  397. *pbLocalSystem = bLocalSystem;
  398. }
  399. bResult = TRUE;
  400. }
  401. catch( _com_error& e )
  402. {
  403. // save the error
  404. WMISaveError( e );
  405. // save the hr value if needed by the caller
  406. if ( NULL != phRes )
  407. {
  408. *phRes = e.Error();
  409. }
  410. SAFE_RELEASE( *ppServices );
  411. bResult = FALSE;
  412. }
  413. return bResult;
  414. }
  415. BOOL
  416. ConnectWmiEx(
  417. IN IWbemLocator *pLocator,
  418. OUT IWbemServices **ppServices,
  419. IN LPCWSTR strServer,
  420. OUT CHString &strUserName,
  421. OUT CHString &strPassword,
  422. OUT COAUTHIDENTITY **ppAuthIdentity,
  423. IN BOOL bNeedPassword,
  424. IN LPCWSTR pwszNamespace,
  425. OUT BOOL *pbLocalSystem
  426. )
  427. /*++
  428. Routine Description:
  429. Connects to wmi.
  430. Arguments:
  431. [IN] pLocator - Pointer to the IWbemLocator object.
  432. [OUT] ppServices - Pointer to IWbemServices object.
  433. [IN] strServer - Holds the server name to connect to.
  434. [OUT] strUserName - Holds the user name.
  435. [OUT] strPassword - Holds the password.
  436. [OUT] ppAuthIdentity - Pointer to authentication structure.
  437. [IN] bNeedPassword - Specifies whether to prompt for password.
  438. [IN] pwszNamespace - Specifies the namespace to connect to.
  439. [OUT] pbLocalSystem - Holds the boolean value to represent whether the server
  440. name is local or not.
  441. Return Value:
  442. TRUE if successfully connected, FALSE if not.
  443. --*/
  444. {
  445. // local variables
  446. HRESULT hRes = 0;
  447. DWORD dwSize = 0;
  448. BOOL bResult = FALSE;
  449. LPWSTR pwszPassword = NULL;
  450. try
  451. {
  452. CHString strBuffer = L"\0";
  453. // clear the error .. if any
  454. SetLastError( WBEM_S_NO_ERROR );
  455. // sometime users want the utility to prompt for the password
  456. // check what user wants the utility to do
  457. if ( TRUE == bNeedPassword && 0 == strPassword.Compare( L"*" ) )
  458. {
  459. // user wants the utility to prompt for the password
  460. // so skip this part and let the flow directly jump the password acceptance part
  461. }
  462. else
  463. {
  464. // try to establish connection to the remote system with the credentials supplied
  465. if ( 0 == strUserName.GetLength() )
  466. {
  467. // user name is empty
  468. // so, it is obvious that password will also be empty
  469. // even if password is specified, we have to ignore that
  470. bResult = ConnectWmi( pLocator, ppServices,
  471. strServer, NULL, NULL, ppAuthIdentity,
  472. FALSE, pwszNamespace, &hRes, pbLocalSystem );
  473. }
  474. else
  475. {
  476. // credentials were supplied
  477. // but password might not be specified ... so check and act accordingly
  478. LPCWSTR pwszTemp = NULL;
  479. BOOL bCheckWithNull = TRUE;
  480. if ( FALSE == bNeedPassword )
  481. {
  482. pwszTemp = strPassword;
  483. bCheckWithNull = FALSE;
  484. }
  485. // ...
  486. bResult = ConnectWmi( pLocator, ppServices, strServer, strUserName,
  487. pwszTemp, ppAuthIdentity, bCheckWithNull, pwszNamespace, &hRes, pbLocalSystem );
  488. }
  489. // check the result ... if successful in establishing connection ... return
  490. if ( TRUE == bResult )
  491. {
  492. SetLastError( hRes ); // set the error code
  493. return TRUE;
  494. }
  495. // now check the kind of error occurred
  496. switch( hRes )
  497. {
  498. case E_ACCESSDENIED:
  499. break;
  500. case WBEM_E_LOCAL_CREDENTIALS:
  501. // needs to do special processing
  502. break;
  503. case WBEM_E_ACCESS_DENIED:
  504. default:
  505. // NOTE: do not check for 'WBEM_E_ACCESS_DENIED'
  506. // this error code says that user with the current credentials is not
  507. // having access permisions to the 'namespace'
  508. WMISaveError( hRes );
  509. return FALSE; // no use of accepting the password .. return failure
  510. }
  511. // if failed in establishing connection to the remote terminal
  512. // even if the password is specifed, then there is nothing to do ... simply return failure
  513. if ( FALSE == bNeedPassword )
  514. {
  515. return( FALSE );
  516. }
  517. }
  518. // check whether user name is specified or not
  519. // if not, get the local system's current user name under whose credentials, the process
  520. // is running
  521. if ( 0 == strUserName.GetLength() )
  522. {
  523. // sub-local variables
  524. LPWSTR pwszUserName = NULL;
  525. // get the required buffer
  526. pwszUserName = strUserName.GetBufferSetLength( MAX_STRING_LENGTH );
  527. // get the user name
  528. DWORD dwUserLength = MAX_STRING_LENGTH;
  529. if ( FALSE == GetUserNameEx( NameSamCompatible, pwszUserName, &dwUserLength ) )
  530. {
  531. // error occured while trying to get the current user info
  532. SaveLastError();
  533. return( FALSE );
  534. }
  535. // release the extra buffer allocated
  536. strUserName.ReleaseBuffer();
  537. }
  538. // get the required buffer
  539. pwszPassword = strPassword.GetBufferSetLength( MAX_STRING_LENGTH );
  540. // accept the password from the user
  541. strBuffer.Format( INPUT_PASSWORD, strUserName );
  542. WriteConsoleW( GetStdHandle( STD_OUTPUT_HANDLE ),
  543. strBuffer, strBuffer.GetLength(), &dwSize, NULL );
  544. bResult = GetPassword( pwszPassword, 256 );
  545. if ( TRUE != bResult )
  546. {
  547. return FALSE;
  548. }
  549. // release the buffer allocated for password
  550. strPassword.ReleaseBuffer();
  551. // now again try to establish the connection using the currently
  552. // supplied credentials
  553. bResult = ConnectWmi( pLocator, ppServices, strServer,
  554. strUserName, strPassword, ppAuthIdentity, FALSE, pwszNamespace, &hRes, pbLocalSystem );
  555. }
  556. catch(CHeap_Exception)
  557. {
  558. WMISaveError( WBEM_E_OUT_OF_MEMORY );
  559. return FALSE;
  560. }
  561. // return the success
  562. return bResult;
  563. }
  564. HRESULT
  565. GetSecurityArguments(
  566. IN IUnknown *pInterface,
  567. OUT DWORD& dwAuthorization,
  568. OUT DWORD& dwAuthentication
  569. )
  570. /*++
  571. Routine Description:
  572. Gets the security arguments for an interface.
  573. Arguments:
  574. [IN] pInterface - Pointer to interface stucture.
  575. [OUT] dwAuthorization - Holds Authorization value.
  576. [OUT] dwAuthentication - Holds the Authentication value.
  577. Return Value:
  578. Returns HRESULT value.
  579. --*/
  580. {
  581. // local variables
  582. HRESULT hRes = S_OK;
  583. DWORD dwAuthnSvc = 0, dwAuthzSvc = 0;
  584. IClientSecurity *pClientSecurity = NULL;
  585. if( NULL == pInterface )
  586. {
  587. return WBEM_E_INVALID_PARAMETER;
  588. }
  589. // try to get the client security services values if possible
  590. hRes = pInterface->QueryInterface( IID_IClientSecurity, (void**) &pClientSecurity );
  591. if ( SUCCEEDED( hRes ) )
  592. {
  593. // got the client security interface
  594. // now try to get the security services values
  595. hRes = pClientSecurity->QueryBlanket( pInterface,
  596. &dwAuthnSvc, &dwAuthzSvc, NULL, NULL, NULL, NULL, NULL );
  597. if ( SUCCEEDED( hRes ) )
  598. {
  599. // we've got the values from the interface
  600. dwAuthentication = dwAuthnSvc;
  601. dwAuthorization = dwAuthzSvc;
  602. }
  603. // release the client security interface
  604. SAFE_RELEASE( pClientSecurity );
  605. }
  606. // return always success
  607. return hRes;
  608. }
  609. HRESULT
  610. SetInterfaceSecurity(
  611. IN IUnknown *pInterface,
  612. IN LPCWSTR pwszUser,
  613. IN LPCWSTR pwszPassword,
  614. OUT COAUTHIDENTITY **ppAuthIdentity
  615. )
  616. /*++
  617. Routine Description:
  618. Sets interface security.
  619. Arguments:
  620. [IN] pInterface - Pointer to the interface to which security has to be set.
  621. [IN] pwszUser - Holds the user name of the server.
  622. [IN] pwszPassword - Hold the password of the user.
  623. [OUT] ppAuthIdentity - Pointer to authentication structure.
  624. Return Value:
  625. returns HRESULT value.
  626. --*/
  627. {
  628. // local variables
  629. HRESULT hRes = S_OK;
  630. CHString strUser;
  631. CHString strDomain;
  632. LPCWSTR pwszUserArg = NULL;
  633. LPCWSTR pwszDomainArg = NULL;
  634. DWORD dwAuthorization = RPC_C_AUTHZ_NONE;
  635. DWORD dwAuthentication = RPC_C_AUTHN_WINNT;
  636. try
  637. {
  638. // check the interface
  639. if ( NULL == pInterface )
  640. {
  641. return WBEM_E_INVALID_PARAMETER;
  642. }
  643. // check the authentity strcuture ... if authentity structure is already ready
  644. // simply invoke the 2nd version of SetInterfaceSecurity
  645. if ( NULL != *ppAuthIdentity )
  646. {
  647. return SetInterfaceSecurity( pInterface, *ppAuthIdentity );
  648. }
  649. // get the current security argument value
  650. // GetSecurityArguments( pInterface, dwAuthorization, dwAuthentication );
  651. // If we are doing trivial case, just pass in a null authenication structure
  652. // for which the current logged in user's credentials will be considered
  653. if ( NULL == pwszUser && NULL == pwszPassword )
  654. {
  655. // set the security
  656. hRes = SetProxyBlanket( pInterface, dwAuthentication, dwAuthorization,
  657. NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
  658. // return the result
  659. return hRes;
  660. }
  661. // parse and find out if the user name contains the domain name
  662. // if contains, extract the domain value from it
  663. LONG lPos = -1;
  664. strDomain = L"";
  665. strUser = pwszUser;
  666. if ( ( lPos = strUser.Find( L'\\' ) ) != -1 )
  667. {
  668. // user name contains domain name ... domain\user format
  669. strDomain = strUser.Left( lPos );
  670. strUser = strUser.Mid( lPos + 1 );
  671. }
  672. // get the domain info if it exists only
  673. if ( 0 != strDomain.GetLength() )
  674. {
  675. pwszDomainArg = strDomain;
  676. }
  677. // get the user info if it exists only
  678. if ( 0 != strUser.GetLength() )
  679. {
  680. pwszUserArg = strUser;
  681. }
  682. // check if authenication info is available or not ...
  683. // initialize the security authenication information ... UNICODE VERSION STRUCTURE
  684. if ( NULL == ppAuthIdentity )
  685. {
  686. return WBEM_E_INVALID_PARAMETER;
  687. }
  688. else if ( NULL == *ppAuthIdentity )
  689. {
  690. hRes = WbemAllocAuthIdentity( pwszUserArg, pwszPassword, pwszDomainArg, ppAuthIdentity );
  691. if ( FAILED(hRes) )
  692. {
  693. return hRes;
  694. }
  695. }
  696. // set the security information to the interface
  697. hRes = SetProxyBlanket( pInterface, dwAuthentication, dwAuthorization, NULL,
  698. RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, *ppAuthIdentity, EOAC_NONE );
  699. }
  700. catch(CHeap_Exception)
  701. {
  702. hRes = WBEM_E_OUT_OF_MEMORY;
  703. }
  704. // return the result
  705. return hRes;
  706. }
  707. HRESULT
  708. SetInterfaceSecurity(
  709. IN IUnknown *pInterface,
  710. IN COAUTHIDENTITY *pAuthIdentity
  711. )
  712. /*++
  713. Routine Description:
  714. Sets the interface security for the interface.
  715. Arguments:
  716. [IN] pInterface - pointer to the interface.
  717. [IN] pAuthIdentity - pointer to authentication structure.
  718. Return Value:
  719. returns HRESULT value.
  720. --*/
  721. {
  722. // local variables
  723. HRESULT hRes = S_OK;
  724. DWORD dwAuthorization = RPC_C_AUTHZ_NONE;
  725. DWORD dwAuthentication = RPC_C_AUTHN_WINNT;
  726. // check the interface
  727. if ( NULL == pInterface )
  728. {
  729. return WBEM_E_INVALID_PARAMETER;
  730. }
  731. // get the current security argument value
  732. hRes = GetSecurityArguments( pInterface, dwAuthorization, dwAuthentication );
  733. if ( FAILED( hRes ) )
  734. {
  735. return hRes;
  736. }
  737. // set the security information to the interface
  738. hRes = SetProxyBlanket( pInterface, dwAuthentication, dwAuthorization, NULL,
  739. RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, pAuthIdentity, EOAC_NONE );
  740. // return the result
  741. return hRes;
  742. }
  743. HRESULT
  744. WINAPI SetProxyBlanket(
  745. IN IUnknown *pInterface,
  746. IN DWORD dwAuthnSvc,
  747. IN DWORD dwAuthzSvc,
  748. IN LPWSTR pwszPrincipal,
  749. IN DWORD dwAuthLevel,
  750. IN DWORD dwImpLevel,
  751. IN RPC_AUTH_IDENTITY_HANDLE pAuthInfo,
  752. IN DWORD dwCapabilities
  753. )
  754. /*++
  755. Routine Description:
  756. Sets proxy blanket for the interface.
  757. Arguments:
  758. [IN] pInterface - pointer to the inteface.
  759. [IN] dwAuthnsvc - Authentication service to use.
  760. [IN] dwAuthzSvc - Authorization service to use.
  761. [IN] pwszPricipal - Server principal name to use with the authentication service.
  762. [IN] dwAuthLevel - Authentication level to use.
  763. [IN] dwImpLevel - Impersonation level to use.
  764. [IN] pAuthInfo - Identity of the client.
  765. [IN] dwCapabilities - Capability flags.
  766. Return Value:
  767. Return HRESULT value.
  768. --*/
  769. {
  770. // local variables
  771. HRESULT hRes = S_OK;
  772. IUnknown *pUnknown = NULL;
  773. IClientSecurity *pClientSecurity = NULL;
  774. // Validate input arguments.
  775. //
  776. // Can't set pAuthInfo if cloaking requested, as cloaking implies
  777. // that the current proxy identity in the impersonated thread (rather
  778. // than the credentials supplied explicitly by the RPC_AUTH_IDENTITY_HANDLE)
  779. // is to be used.
  780. // See MSDN info on CoSetProxyBlanket for more details.
  781. //
  782. if( ( NULL == pInterface ) ||
  783. ( ( dwCapabilities & (EOAC_STATIC_CLOAKING | EOAC_DYNAMIC_CLOAKING) ) &&
  784. ( NULL != pAuthInfo ) )
  785. )
  786. {
  787. return( WBEM_E_INVALID_PARAMETER );
  788. }
  789. // get the IUnknown interface ... to check whether this is a valid interface or not
  790. hRes = pInterface->QueryInterface( IID_IUnknown, (void **) &pUnknown );
  791. if ( FAILED( hRes ) )
  792. {
  793. return hRes;
  794. }
  795. // now get the client security interface
  796. hRes = pInterface->QueryInterface( IID_IClientSecurity, (void **) &pClientSecurity );
  797. if ( FAILED( hRes ) )
  798. {
  799. SAFE_RELEASE( pUnknown );
  800. return hRes;
  801. }
  802. // now set the security
  803. hRes = pClientSecurity->SetBlanket( pInterface, dwAuthnSvc, dwAuthzSvc, pwszPrincipal,
  804. dwAuthLevel, dwImpLevel, pAuthInfo, dwCapabilities );
  805. if( FAILED( hRes ) )
  806. {
  807. SAFE_RELEASE( pUnknown );
  808. SAFE_RELEASE( pClientSecurity );
  809. return hRes;
  810. }
  811. // release the security interface
  812. SAFE_RELEASE( pClientSecurity );
  813. // we should check the auth identity structure. if exists .. set for IUnknown also
  814. if ( NULL != pAuthInfo )
  815. {
  816. hRes = pUnknown->QueryInterface( IID_IClientSecurity, (void **) &pClientSecurity );
  817. if ( SUCCEEDED( hRes ) )
  818. {
  819. // set security authentication
  820. hRes = pClientSecurity->SetBlanket(
  821. pUnknown, dwAuthnSvc, dwAuthzSvc, pwszPrincipal,
  822. dwAuthLevel, dwImpLevel, pAuthInfo, dwCapabilities );
  823. // release
  824. SAFE_RELEASE( pClientSecurity );
  825. }
  826. else if ( E_NOINTERFACE == hRes )
  827. {
  828. hRes = S_OK; // ignore no interface errors
  829. }
  830. }
  831. // release the IUnknown
  832. SAFE_RELEASE( pUnknown );
  833. // return the result
  834. return hRes;
  835. }
  836. HRESULT
  837. WINAPI WbemAllocAuthIdentity(
  838. IN LPCWSTR pwszUser,
  839. IN LPCWSTR pwszPassword,
  840. IN LPCWSTR pwszDomain,
  841. OUT COAUTHIDENTITY **ppAuthIdent
  842. )
  843. /*++
  844. Routine Description:
  845. Allocate memory for authentication variables.
  846. Arguments:
  847. [IN] pwszUser - User name.
  848. [IN] pwszPassword - Password.
  849. [IN] pwszDomain - Domain name.
  850. [OUT] ppAuthIdent - Pointer to authentication structure.
  851. Return Value:
  852. Returns HRESULT value.
  853. --*/
  854. {
  855. // local variables
  856. COAUTHIDENTITY *pAuthIdent = NULL;
  857. // validate the input parameter
  858. if ( NULL == ppAuthIdent )
  859. {
  860. return WBEM_E_INVALID_PARAMETER;
  861. }
  862. // allocation thru COM API
  863. pAuthIdent = ( COAUTHIDENTITY* ) CoTaskMemAlloc( sizeof( COAUTHIDENTITY ) );
  864. if ( pAuthIdent == NULL )
  865. {
  866. return WBEM_E_OUT_OF_MEMORY;
  867. }
  868. // init with 0's
  869. SecureZeroMemory( ( void* ) pAuthIdent, sizeof( COAUTHIDENTITY ) );
  870. //
  871. // Allocate needed memory and copy in data. Cleanup if anything goes wrong
  872. // user
  873. if ( NULL != pwszUser )
  874. {
  875. // allocate memory for user
  876. LONG lLength = StringLength( pwszUser, 0 );
  877. pAuthIdent->User = ( LPWSTR ) CoTaskMemAlloc( (lLength + 1) * sizeof( WCHAR ) );
  878. if ( NULL == pAuthIdent->User )
  879. {
  880. WbemFreeAuthIdentity( &pAuthIdent );
  881. return WBEM_E_OUT_OF_MEMORY;
  882. }
  883. // set the length and do copy contents
  884. pAuthIdent->UserLength = lLength;
  885. StringCopy( pAuthIdent->User, pwszUser, (lLength + 1) );
  886. }
  887. // domain
  888. if ( NULL != pwszDomain )
  889. {
  890. // allocate memory for domain
  891. LONG lLength = StringLength( pwszDomain, 0 );
  892. pAuthIdent->Domain = ( LPWSTR ) CoTaskMemAlloc( (lLength + 1) * sizeof( WCHAR ) );
  893. if ( NULL == pAuthIdent->Domain )
  894. {
  895. WbemFreeAuthIdentity( &pAuthIdent );
  896. return WBEM_E_OUT_OF_MEMORY;
  897. }
  898. // set the length and do copy contents
  899. pAuthIdent->DomainLength = lLength;
  900. StringCopy( pAuthIdent->Domain, pwszDomain, (lLength + 1) );
  901. }
  902. // passsord
  903. if ( NULL != pwszPassword )
  904. {
  905. // allocate memory for passsord
  906. LONG lLength = StringLength( pwszPassword, 0 );
  907. pAuthIdent->Password = ( LPWSTR ) CoTaskMemAlloc( (lLength + 1) * sizeof( WCHAR ) );
  908. if ( NULL == pAuthIdent->Password )
  909. {
  910. WbemFreeAuthIdentity( &pAuthIdent );
  911. return WBEM_E_OUT_OF_MEMORY;
  912. }
  913. // set the length and do copy contents
  914. pAuthIdent->PasswordLength = lLength;
  915. StringCopy( pAuthIdent->Password, pwszPassword, (lLength + 1) );
  916. }
  917. // type of the structure
  918. pAuthIdent->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  919. // final set the address to out parameter
  920. *ppAuthIdent = pAuthIdent;
  921. // return result
  922. return S_OK;
  923. }
  924. VOID
  925. WINAPI WbemFreeAuthIdentity(
  926. IN COAUTHIDENTITY** ppAuthIdentity
  927. )
  928. /*++
  929. Routine Description:
  930. Frees the memory of authentication stucture variable.
  931. Arguments:
  932. [IN] ppAuthIdentity - Pointer to authentication structure.
  933. Return Value:
  934. none.
  935. --*/
  936. {
  937. // make sure we have a pointer, then walk the structure members and cleanup.
  938. if ( NULL != *ppAuthIdentity )
  939. {
  940. // free the memory allocated for user
  941. if ( NULL != (*ppAuthIdentity)->User )
  942. {
  943. CoTaskMemFree( (*ppAuthIdentity)->User );
  944. (*ppAuthIdentity)->User = NULL;
  945. }
  946. // free the memory allocated for password
  947. if ( NULL != (*ppAuthIdentity)->Password )
  948. {
  949. CoTaskMemFree( (*ppAuthIdentity)->Password );
  950. (*ppAuthIdentity)->Password = NULL;
  951. }
  952. // free the memory allocated for domain
  953. if ( NULL != (*ppAuthIdentity)->Domain )
  954. {
  955. CoTaskMemFree( (*ppAuthIdentity)->Domain );
  956. (*ppAuthIdentity)->Domain = NULL;
  957. }
  958. // final the structure
  959. CoTaskMemFree( *ppAuthIdentity );
  960. *ppAuthIdentity = NULL;
  961. }
  962. }
  963. VOID
  964. WMISaveError(
  965. IN HRESULT hResError
  966. )
  967. /*++
  968. Routine Description:
  969. Gets WMI error description.
  970. Arguments:
  971. [IN] hResError - Contain error value.
  972. Return Value:
  973. none.
  974. --*/
  975. {
  976. // local variables
  977. HRESULT hRes;
  978. IWbemStatusCodeText *pWbemStatus = NULL;
  979. CHString strBuffer = L"\0";
  980. // if the error is win32 based, choose FormatMessage to get the message
  981. switch( hResError )
  982. {
  983. case E_ACCESSDENIED: // Message: "Access Denied"
  984. case ERROR_NO_SUCH_USER: // Message: "The specified user does not exist."
  985. {
  986. // change the error message to "Logon failure: unknown user name or bad password."
  987. if ( E_ACCESSDENIED == hResError )
  988. {
  989. hResError = ERROR_LOGON_FAILURE;
  990. }
  991. // ...
  992. SetLastError( hResError );
  993. SaveLastError();
  994. return;
  995. }
  996. case REGDB_E_CLASSNOTREG: // Message: Class not registered.
  997. {
  998. SetLastError( hResError );
  999. SetReason( ERROR_REMOTE_INCOMPATIBLE );
  1000. return;
  1001. }
  1002. }
  1003. try
  1004. {
  1005. // get the pointer to buffer
  1006. LPWSTR pwszBuffer = NULL;
  1007. pwszBuffer = strBuffer.GetBufferSetLength( MAX_STRING_LENGTH );
  1008. // get the wbem specific status code text
  1009. hRes = CoCreateInstance( CLSID_WbemStatusCodeText,
  1010. NULL, CLSCTX_INPROC_SERVER, IID_IWbemStatusCodeText, ( LPVOID* ) &pWbemStatus );
  1011. // check whether we got the interface or not
  1012. if ( SUCCEEDED( hRes ) )
  1013. {
  1014. // get the error message
  1015. BSTR bstr = NULL;
  1016. hRes = pWbemStatus->GetErrorCodeText( hResError, 0, 0, &bstr );
  1017. if ( SUCCEEDED( hRes ) )
  1018. {
  1019. // get the error message in proper format
  1020. StringCopyW( pwszBuffer, bstr, MAX_STRING_LENGTH );
  1021. // free the BSTR
  1022. SysFreeString( bstr );
  1023. bstr = NULL;
  1024. // now release status code interface
  1025. SAFE_RELEASE( pWbemStatus );
  1026. }
  1027. else
  1028. {
  1029. // failed to get the error message ... get the com specific error message
  1030. _com_issue_error( hResError );
  1031. }
  1032. }
  1033. else
  1034. {
  1035. // failed to get the error message ... get the com specific error message
  1036. _com_issue_error( hResError );
  1037. }
  1038. // release the buffer
  1039. strBuffer.ReleaseBuffer();
  1040. // set the reason
  1041. strBuffer += L"\n";
  1042. SetReason( strBuffer );
  1043. }
  1044. catch( _com_error& e )
  1045. {
  1046. try
  1047. {
  1048. // get the error message
  1049. strBuffer.ReleaseBuffer();
  1050. if ( NULL != e.ErrorMessage() )
  1051. {
  1052. strBuffer = e.ErrorMessage();
  1053. }
  1054. }
  1055. catch( CHeap_Exception )
  1056. {
  1057. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1058. SaveLastError();
  1059. }
  1060. }
  1061. catch(CHeap_Exception)
  1062. {
  1063. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1064. SaveLastError();
  1065. return;
  1066. }
  1067. }
  1068. DWORD
  1069. GetTargetVersionEx(
  1070. IN IWbemServices* pWbemServices,
  1071. IN COAUTHIDENTITY* pAuthIdentity
  1072. )
  1073. /*++
  1074. Routine Description:
  1075. Get the OS version of the target machine.
  1076. Arguments:
  1077. [IN] pWbemServices - Pointer to IWbemServices object.
  1078. [IN] pAuthIdentity - Poointer to authentication structure.
  1079. Return Value:
  1080. 0 if failed to get version number, else non-zero value.
  1081. --*/
  1082. {
  1083. // local variables
  1084. HRESULT hRes = S_OK;
  1085. LONG lPos = 0;
  1086. DWORD dwMajor = 0;
  1087. DWORD dwMinor = 0;
  1088. DWORD dwVersion = 0;
  1089. ULONG ulReturned = 0;
  1090. IWbemClassObject* pWbemObject = NULL;
  1091. IEnumWbemClassObject* pWbemInstances = NULL;
  1092. CHString strVersion;
  1093. // Clear any errors.
  1094. SetLastError( WBEM_S_NO_ERROR );
  1095. // Check the input value
  1096. if ( NULL == pWbemServices )
  1097. {
  1098. WMISaveError( WBEM_E_INVALID_PARAMETER );
  1099. return 0;
  1100. }
  1101. try
  1102. {
  1103. // get the OS information
  1104. SAFE_EXECUTE( pWbemServices->CreateInstanceEnum(
  1105. _bstr_t( CLASS_CIMV2_Win32_OperatingSystem ),
  1106. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pWbemInstances ) );
  1107. // set the security on the enumerated object
  1108. SAFE_EXECUTE( SetInterfaceSecurity( pWbemInstances, pAuthIdentity ) );
  1109. // get the enumerated objects information
  1110. // NOTE: This needs to be traversed only one time.
  1111. SAFE_EXECUTE( pWbemInstances->Next( WBEM_INFINITE, 1, &pWbemObject, &ulReturned ) );
  1112. // to be on safer side ... check the count of objects returned
  1113. if ( 0 == ulReturned )
  1114. {
  1115. // release the interfaces
  1116. WMISaveError( WBEM_S_FALSE );
  1117. SAFE_RELEASE( pWbemObject );
  1118. SAFE_RELEASE( pWbemInstances );
  1119. return 0;
  1120. }
  1121. // now get the os version value
  1122. if ( FALSE == PropertyGet( pWbemObject, L"Version", strVersion ) )
  1123. {
  1124. // release the interfaces
  1125. SAFE_RELEASE( pWbemObject );
  1126. SAFE_RELEASE( pWbemInstances );
  1127. return 0;
  1128. }
  1129. // release the interfaces .. we dont need them furthur
  1130. SAFE_RELEASE( pWbemObject );
  1131. SAFE_RELEASE( pWbemInstances );
  1132. //
  1133. // now determine the os version
  1134. dwMajor = dwMinor = 0;
  1135. // get the major version
  1136. lPos = strVersion.Find( L'.' );
  1137. if ( -1 == lPos )
  1138. {
  1139. // the version string itself is version ... THIS WILL NEVER HAPPEN
  1140. if( FALSE == IsNumeric( strVersion, 10, FALSE ) )
  1141. {
  1142. return 0;
  1143. }
  1144. dwMajor = AsLong( strVersion, 10 );
  1145. }
  1146. else
  1147. {
  1148. // major version
  1149. if( FALSE == IsNumeric( strVersion.Mid( 0, lPos ), 10, FALSE ) )
  1150. {
  1151. return 0;
  1152. }
  1153. dwMajor = AsLong( strVersion.Mid( 0, lPos ), 10 );
  1154. // get the minor version
  1155. strVersion = strVersion.Mid( lPos + 1 );
  1156. lPos = strVersion.Find( L'.' );
  1157. if ( -1 == lPos )
  1158. {
  1159. if( FALSE == IsNumeric( strVersion, 10, FALSE ) )
  1160. {
  1161. return 0;
  1162. }
  1163. dwMinor = AsLong( strVersion, 10 );
  1164. }
  1165. else
  1166. {
  1167. if( FALSE == IsNumeric( strVersion.Mid( 0, lPos ), 10, FALSE ) )
  1168. {
  1169. return 0;
  1170. }
  1171. dwMinor = AsLong( strVersion.Mid( 0, lPos ), 10 );
  1172. }
  1173. }
  1174. // mix the version info
  1175. dwVersion = dwMajor * 1000 + dwMinor;
  1176. }
  1177. catch( _com_error& e )
  1178. {
  1179. WMISaveError( e );
  1180. SAFE_RELEASE( pWbemObject );
  1181. SAFE_RELEASE( pWbemInstances );
  1182. return 0;
  1183. }
  1184. catch(CHeap_Exception)
  1185. {
  1186. WMISaveError( WBEM_E_OUT_OF_MEMORY );
  1187. SAFE_RELEASE( pWbemObject );
  1188. SAFE_RELEASE( pWbemInstances );
  1189. return 0;
  1190. }
  1191. // return
  1192. return dwVersion;
  1193. }
  1194. BOOL
  1195. PropertyGet(
  1196. IN IWbemClassObject* pWmiObject,
  1197. IN LPCWSTR pwszProperty,
  1198. OUT CHString& strValue,
  1199. IN LPCWSTR pwszDefault
  1200. )
  1201. /*++
  1202. Routine Description:
  1203. Gets the value of the property from the WMI class object in string format
  1204. Arguments:
  1205. [IN] pWmiObject : pointer to the WBEM class object
  1206. [IN] pwszProperty : the name of the property to retrieve
  1207. [OUT] strValue : variable to hold the retrieved property
  1208. [IN] pwszDefault : string containing the default value for the property
  1209. Return Value:
  1210. TRUE on success
  1211. FALSE on failure
  1212. NOTE: THIS FUNCTION SAVES LAST ERROR OCCURED. IF FALSE IS RETURNED THEN ERROR
  1213. OCCURED STRING CAN BE RETRIEVED BY CALLING 'GetReason()'.
  1214. --*/
  1215. {
  1216. // local variables
  1217. HRESULT hRes = S_OK;
  1218. _variant_t var;
  1219. // Clear any errors.
  1220. SetLastError( WBEM_S_NO_ERROR );
  1221. strValue.Empty();
  1222. try
  1223. {
  1224. // first copy the default value
  1225. strValue = pwszDefault;
  1226. // Validate input arguments.
  1227. if ( ( NULL == pWmiObject ) ||
  1228. ( NULL == pwszProperty ) )
  1229. {
  1230. _com_issue_error( WBEM_E_INVALID_PARAMETER );
  1231. }
  1232. // get the property value
  1233. hRes = PropertyGet( pWmiObject, pwszProperty, var );
  1234. if ( FAILED( hRes ) )
  1235. {
  1236. _com_issue_error( hRes );
  1237. }
  1238. // Get the value
  1239. // If 'var' does not contain value of requested type
  1240. // then default value is returned.
  1241. if ( VT_BSTR == V_VT( &var ) )
  1242. {
  1243. strValue = (LPCWSTR) _bstr_t( var );
  1244. }
  1245. }
  1246. catch( _com_error& e )
  1247. {
  1248. WMISaveError( e );
  1249. return FALSE;
  1250. }
  1251. catch( CHeap_Exception )
  1252. {
  1253. WMISaveError( WBEM_E_OUT_OF_MEMORY );
  1254. return FALSE;
  1255. }
  1256. // return
  1257. return TRUE;
  1258. }
  1259. HRESULT
  1260. PropertyGet(
  1261. IN IWbemClassObject* pWmiObject,
  1262. IN LPCWSTR pwszProperty,
  1263. OUT _variant_t& varValue
  1264. )
  1265. /*++
  1266. Routine Description:
  1267. Gets the value of the property from the WMI class object
  1268. Arguments:
  1269. [IN] pWmiObject : pointer to the WBEM class object
  1270. [IN] pwszProperty : property name
  1271. [OUT] varValue : value of the property
  1272. Return Value:
  1273. HRESULT
  1274. --*/
  1275. {
  1276. // local variables
  1277. HRESULT hRes = S_OK;
  1278. VARIANT vtValue;
  1279. // Validate input arguments.
  1280. if ( ( NULL == pWmiObject ) ||
  1281. ( NULL == pwszProperty ) )
  1282. {
  1283. return WBEM_E_INVALID_PARAMETER;
  1284. }
  1285. try
  1286. {
  1287. // initialize the variant and then get the value of the specified property
  1288. VariantInit( &vtValue );
  1289. // Call 'Get' method to retireve the value from WMI.
  1290. hRes = pWmiObject->Get( _bstr_t( pwszProperty ), 0, &vtValue, NULL, NULL );
  1291. if ( FAILED( hRes ) )
  1292. {
  1293. // Clear the variant variable
  1294. VariantClear( &vtValue );
  1295. // Return error.
  1296. return hRes;
  1297. }
  1298. // set the value
  1299. varValue = vtValue;
  1300. }
  1301. catch( _com_error& e )
  1302. {
  1303. hRes = e.Error();
  1304. }
  1305. // Clear the variables.
  1306. VariantClear( &vtValue );
  1307. // Return.
  1308. return hRes;
  1309. }