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.

2319 lines
54 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. Helper.cpp
  5. Abstract:
  6. Various funtion encapsulate HELP user account
  7. validation, creating.
  8. Author:
  9. HueiWang 2/17/2000
  10. --*/
  11. #include "stdafx.h"
  12. #include <time.h>
  13. #include <stdio.h>
  14. #include <windows.h>
  15. #include <ntsecapi.h>
  16. #include <lmcons.h>
  17. #include <lm.h>
  18. #include <sspi.h>
  19. #include <wtsapi32.h>
  20. #include <winbase.h>
  21. #include <security.h>
  22. #include <Sddl.h>
  23. #define STRSAFE_NO_DEPRECATE
  24. #include <strsafe.h>
  25. #include "Helper.h"
  26. #if DBG
  27. void
  28. DebugPrintf(
  29. IN LPCTSTR format, ...
  30. )
  31. /*++
  32. Routine Description:
  33. sprintf() like wrapper around OutputDebugString().
  34. Parameters:
  35. hConsole : Handle to console.
  36. format : format string.
  37. Returns:
  38. None.
  39. Note:
  40. To be replace by generic tracing code.
  41. ++*/
  42. {
  43. TCHAR buf[8096]; // max. error text
  44. DWORD dump;
  45. HRESULT hr;
  46. va_list marker;
  47. va_start(marker, format);
  48. SYSTEMTIME sysTime;
  49. GetSystemTime(&sysTime);
  50. try {
  51. hr = StringCchPrintf(
  52. buf,
  53. sizeof(buf)/sizeof(buf[0]),
  54. _TEXT(" %d [%d:%d:%d:%d:%d.%d] : "),
  55. GetCurrentThreadId(),
  56. sysTime.wMonth,
  57. sysTime.wDay,
  58. sysTime.wHour,
  59. sysTime.wMinute,
  60. sysTime.wSecond,
  61. sysTime.wMilliseconds
  62. );
  63. if( S_OK == hr )
  64. {
  65. hr = StringCchVPrintf(
  66. buf + lstrlen(buf),
  67. sizeof(buf)/sizeof(buf[0]) - lstrlen(buf),
  68. format,
  69. marker
  70. );
  71. }
  72. if( S_OK == hr || STRSAFE_E_INSUFFICIENT_BUFFER == hr )
  73. {
  74. // StringCchPrintf() and StringCchVPrintf() will
  75. // truncate string and NULL terminate buffer so
  76. // we are safe to dump out whatever we got.
  77. OutputDebugString(buf);
  78. }
  79. else
  80. {
  81. OutputDebugString( _TEXT("Debug String Too Long...\n") );
  82. }
  83. }
  84. catch(...) {
  85. }
  86. va_end(marker);
  87. return;
  88. }
  89. #endif
  90. void
  91. UnixTimeToFileTime(
  92. time_t t,
  93. LPFILETIME pft
  94. )
  95. {
  96. LARGE_INTEGER li;
  97. li.QuadPart = Int32x32To64(t, 10000000) + 116444736000000000;
  98. pft->dwHighDateTime = li.HighPart;
  99. pft->dwLowDateTime = li.LowPart;
  100. }
  101. /*------------------------------------------------------------------------
  102. BOOL IsUserAdmin(BOOL)
  103. returns TRUE if user is an admin
  104. FALSE if user is not an admin
  105. ------------------------------------------------------------------------*/
  106. DWORD
  107. IsUserAdmin(
  108. BOOL* bMember
  109. )
  110. {
  111. PSID psidAdministrators;
  112. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  113. DWORD dwStatus=ERROR_SUCCESS;
  114. do {
  115. if(!AllocateAndInitializeSid(&siaNtAuthority,
  116. 2,
  117. SECURITY_BUILTIN_DOMAIN_RID,
  118. DOMAIN_ALIAS_RID_ADMINS,
  119. 0, 0, 0, 0, 0, 0,
  120. &psidAdministrators))
  121. {
  122. dwStatus=GetLastError();
  123. continue;
  124. }
  125. // assume that we don't find the admin SID.
  126. if(!CheckTokenMembership(NULL,
  127. psidAdministrators,
  128. bMember))
  129. {
  130. dwStatus=GetLastError();
  131. }
  132. FreeSid(psidAdministrators);
  133. } while(FALSE);
  134. return dwStatus;
  135. }
  136. DWORD
  137. GetRandomNumber(
  138. HCRYPTPROV hProv,
  139. DWORD* pdwRandom
  140. )
  141. /*++
  142. --*/
  143. {
  144. DWORD dwStatus = ERROR_SUCCESS;
  145. if( NULL == hProv )
  146. {
  147. dwStatus = ERROR_INVALID_PARAMETER;
  148. }
  149. else
  150. {
  151. if( !CryptGenRandom(hProv, sizeof(*pdwRandom), (PBYTE)pdwRandom) )
  152. {
  153. dwStatus = GetLastError();
  154. }
  155. }
  156. MYASSERT( ERROR_SUCCESS == dwStatus );
  157. return dwStatus;
  158. }
  159. //-----------------------------------------------------
  160. DWORD
  161. ShuffleCharArray(
  162. IN HCRYPTPROV hProv,
  163. IN int iSizeOfTheArray,
  164. IN OUT TCHAR *lptsTheArray
  165. )
  166. /*++
  167. Routine Description:
  168. Random shuffle content of a char. array.
  169. Parameters:
  170. iSizeOfTheArray : Size of array.
  171. lptsTheArray : On input, the array to be randomly shuffer,
  172. on output, the shuffled array.
  173. Returns:
  174. None.
  175. Note:
  176. Code Modified from winsta\server\wstrpc.c
  177. --*/
  178. {
  179. int i;
  180. int iTotal;
  181. DWORD dwStatus = ERROR_SUCCESS;
  182. if( NULL == hProv )
  183. {
  184. dwStatus = ERROR_INVALID_PARAMETER;
  185. }
  186. else
  187. {
  188. iTotal = iSizeOfTheArray / sizeof(TCHAR);
  189. for (i = 0; i < iTotal && ERROR_SUCCESS == dwStatus; i++)
  190. {
  191. DWORD RandomNum;
  192. TCHAR c;
  193. dwStatus = GetRandomNumber(hProv, &RandomNum);
  194. if( ERROR_SUCCESS == dwStatus )
  195. {
  196. c = lptsTheArray[i];
  197. lptsTheArray[i] = lptsTheArray[RandomNum % iTotal];
  198. lptsTheArray[RandomNum % iTotal] = c;
  199. }
  200. }
  201. }
  202. return dwStatus;
  203. }
  204. //-----------------------------------------------------
  205. DWORD
  206. GenerateRandomBytes(
  207. IN DWORD dwSize,
  208. IN OUT LPBYTE pbBuffer
  209. )
  210. /*++
  211. Description:
  212. Generate fill buffer with random bytes.
  213. Parameters:
  214. dwSize : Size of buffer pbBuffer point to.
  215. pbBuffer : Pointer to buffer to hold the random bytes.
  216. Returns:
  217. TRUE/FALSE
  218. --*/
  219. {
  220. HCRYPTPROV hProv = NULL;
  221. DWORD dwStatus = ERROR_SUCCESS;
  222. //
  223. // Create a Crypto Provider to generate random number
  224. //
  225. if( !CryptAcquireContext(
  226. &hProv,
  227. NULL,
  228. NULL,
  229. PROV_RSA_FULL,
  230. CRYPT_VERIFYCONTEXT
  231. ) )
  232. {
  233. dwStatus = GetLastError();
  234. goto CLEANUPANDEXIT;
  235. }
  236. if( !CryptGenRandom(hProv, dwSize, pbBuffer) )
  237. {
  238. dwStatus = GetLastError();
  239. }
  240. CLEANUPANDEXIT:
  241. if( NULL != hProv )
  242. {
  243. CryptReleaseContext( hProv, 0 );
  244. }
  245. return dwStatus;
  246. }
  247. DWORD
  248. GenerateRandomString(
  249. IN DWORD dwSizeRandomSeed,
  250. IN OUT LPTSTR* pszRandomString
  251. )
  252. /*++
  253. --*/
  254. {
  255. PBYTE lpBuffer = NULL;
  256. DWORD dwStatus = ERROR_SUCCESS;
  257. BOOL bSuccess;
  258. DWORD cbConvertString = 0;
  259. if( 0 == dwSizeRandomSeed || NULL == pszRandomString )
  260. {
  261. dwStatus = ERROR_INVALID_PARAMETER;
  262. MYASSERT(FALSE);
  263. goto CLEANUPANDEXIT;
  264. }
  265. *pszRandomString = NULL;
  266. lpBuffer = (PBYTE)LocalAlloc( LPTR, dwSizeRandomSeed );
  267. if( NULL == lpBuffer )
  268. {
  269. dwStatus = GetLastError();
  270. goto CLEANUPANDEXIT;
  271. }
  272. dwStatus = GenerateRandomBytes( dwSizeRandomSeed, lpBuffer );
  273. if( ERROR_SUCCESS != dwStatus )
  274. {
  275. goto CLEANUPANDEXIT;
  276. }
  277. // Convert to string
  278. bSuccess = CryptBinaryToString(
  279. lpBuffer,
  280. dwSizeRandomSeed,
  281. CRYPT_STRING_BASE64,
  282. 0,
  283. &cbConvertString
  284. );
  285. if( FALSE == bSuccess )
  286. {
  287. dwStatus = GetLastError();
  288. goto CLEANUPANDEXIT;
  289. }
  290. *pszRandomString = (LPTSTR)LocalAlloc( LPTR, (cbConvertString+1)*sizeof(TCHAR) );
  291. if( NULL == *pszRandomString )
  292. {
  293. dwStatus = GetLastError();
  294. goto CLEANUPANDEXIT;
  295. }
  296. bSuccess = CryptBinaryToString(
  297. lpBuffer,
  298. dwSizeRandomSeed,
  299. CRYPT_STRING_BASE64,
  300. *pszRandomString,
  301. &cbConvertString
  302. );
  303. if( FALSE == bSuccess )
  304. {
  305. dwStatus = GetLastError();
  306. }
  307. else
  308. {
  309. if( (*pszRandomString)[cbConvertString - 1] == '\n' &&
  310. (*pszRandomString)[cbConvertString - 2] == '\r' )
  311. {
  312. (*pszRandomString)[cbConvertString - 2] = 0;
  313. }
  314. }
  315. CLEANUPANDEXIT:
  316. if( ERROR_SUCCESS != dwStatus )
  317. {
  318. if( NULL != *pszRandomString )
  319. {
  320. LocalFree(*pszRandomString);
  321. }
  322. }
  323. if( NULL != lpBuffer )
  324. {
  325. LocalFree(lpBuffer);
  326. }
  327. return dwStatus;
  328. }
  329. DWORD
  330. CreatePassword(
  331. OUT TCHAR *pszPassword,
  332. IN DWORD nLength
  333. )
  334. /*++
  335. Routine Description:
  336. Routine to randomly create a password.
  337. Parameters:
  338. pszPassword : Pointer to buffer to received a randomly generated
  339. password, buffer must be at least
  340. MAX_HELPACCOUNT_PASSWORD+1 characters.
  341. Returns:
  342. None.
  343. Note:
  344. Code copied from winsta\server\wstrpc.c
  345. --*/
  346. {
  347. HCRYPTPROV hProv = NULL;
  348. int iTotal = 0;
  349. DWORD RandomNum = 0;
  350. int i;
  351. DWORD dwStatus = ERROR_SUCCESS;
  352. TCHAR six2pr[64] =
  353. {
  354. _T('A'), _T('B'), _T('C'), _T('D'), _T('E'), _T('F'), _T('G'),
  355. _T('H'), _T('I'), _T('J'), _T('K'), _T('L'), _T('M'), _T('N'),
  356. _T('O'), _T('P'), _T('Q'), _T('R'), _T('S'), _T('T'), _T('U'),
  357. _T('V'), _T('W'), _T('X'), _T('Y'), _T('Z'), _T('a'), _T('b'),
  358. _T('c'), _T('d'), _T('e'), _T('f'), _T('g'), _T('h'), _T('i'),
  359. _T('j'), _T('k'), _T('l'), _T('m'), _T('n'), _T('o'), _T('p'),
  360. _T('q'), _T('r'), _T('s'), _T('t'), _T('u'), _T('v'), _T('w'),
  361. _T('x'), _T('y'), _T('z'), _T('0'), _T('1'), _T('2'), _T('3'),
  362. _T('4'), _T('5'), _T('6'), _T('7'), _T('8'), _T('9'), _T('*'),
  363. _T('_')
  364. };
  365. TCHAR something1[12] =
  366. {
  367. _T('!'), _T('@'), _T('#'), _T('$'), _T('^'), _T('&'), _T('*'),
  368. _T('('), _T(')'), _T('-'), _T('+'), _T('=')
  369. };
  370. TCHAR something2[10] =
  371. {
  372. _T('0'), _T('1'), _T('2'), _T('3'), _T('4'), _T('5'), _T('6'),
  373. _T('7'), _T('8'), _T('9')
  374. };
  375. TCHAR something3[26] =
  376. {
  377. _T('A'), _T('B'), _T('C'), _T('D'), _T('E'), _T('F'), _T('G'),
  378. _T('H'), _T('I'), _T('J'), _T('K'), _T('L'), _T('M'), _T('N'),
  379. _T('O'), _T('P'), _T('Q'), _T('R'), _T('S'), _T('T'), _T('U'),
  380. _T('V'), _T('W'), _T('X'), _T('Y'), _T('Z')
  381. };
  382. TCHAR something4[26] =
  383. {
  384. _T('a'), _T('b'), _T('c'), _T('d'), _T('e'), _T('f'), _T('g'),
  385. _T('h'), _T('i'), _T('j'), _T('k'), _T('l'), _T('m'), _T('n'),
  386. _T('o'), _T('p'), _T('q'), _T('r'), _T('s'), _T('t'), _T('u'),
  387. _T('v'), _T('w'), _T('x'), _T('y'), _T('z')
  388. };
  389. if( nLength < MIN_HELPACCOUNT_PASSWORD ) {
  390. // This can't happen as function is called internally with
  391. // buffer of MAX_HELPACCOUNT_PASSWORD so assert here.
  392. dwStatus = ERROR_INSUFFICIENT_BUFFER;
  393. ASSERT( FALSE );
  394. goto CLEANUPANDEXIT;
  395. }
  396. //
  397. // Create a Crypto Provider to generate random number
  398. //
  399. if( !CryptAcquireContext(
  400. &hProv,
  401. NULL,
  402. NULL,
  403. PROV_RSA_FULL,
  404. CRYPT_VERIFYCONTEXT
  405. ) )
  406. {
  407. dwStatus = GetLastError();
  408. goto CLEANUPANDEXIT;
  409. }
  410. //
  411. // Shuffle around the six2pr[] array.
  412. //
  413. dwStatus = ShuffleCharArray(hProv, sizeof(six2pr), six2pr);
  414. if( ERROR_SUCCESS != dwStatus )
  415. {
  416. goto CLEANUPANDEXIT;
  417. }
  418. //
  419. // Assign each character of the password array.
  420. //
  421. iTotal = sizeof(six2pr) / sizeof(TCHAR);
  422. for (i=0; i<nLength && ERROR_SUCCESS == dwStatus; i++)
  423. {
  424. dwStatus = GetRandomNumber(hProv, &RandomNum);
  425. if( ERROR_SUCCESS == dwStatus )
  426. {
  427. pszPassword[i]=six2pr[RandomNum%iTotal];
  428. }
  429. }
  430. if( ERROR_SUCCESS != dwStatus )
  431. {
  432. MYASSERT(FALSE);
  433. goto CLEANUPANDEXIT;
  434. }
  435. //
  436. // In order to meet a possible policy set upon passwords, replace chars
  437. // 2 through 5 with these:
  438. //
  439. // 1) something from !@#$%^&*()-+=
  440. // 2) something from 1234567890
  441. // 3) an uppercase letter
  442. // 4) a lowercase letter
  443. //
  444. //
  445. // Security: We need to randomize where we put special characters,
  446. // randomindex[0] is where we going to put symbol in pszPassword
  447. // randomindex[1] is where we going to put digit in pszPassword
  448. // randomindex[2] is where we going to put uppercase letter in pszPassword
  449. // randomindex[3] is where we going to put lowercase letter in pszPassword
  450. DWORD randomindex[4];
  451. int indexassigned = 0;
  452. // randomly pick one characters in password to gtes char. from something1.
  453. dwStatus = GetRandomNumber(hProv, &RandomNum);
  454. if( ERROR_SUCCESS != dwStatus )
  455. {
  456. goto CLEANUPANDEXIT;
  457. }
  458. randomindex[0] = RandomNum % nLength;
  459. indexassigned++;
  460. while( ERROR_SUCCESS == dwStatus && indexassigned < sizeof(randomindex)/sizeof(randomindex[0]) )
  461. {
  462. dwStatus = GetRandomNumber(hProv, &RandomNum);
  463. if( ERROR_SUCCESS == dwStatus )
  464. {
  465. RandomNum = RandomNum % nLength;
  466. // make sure we don't re-use the index.
  467. for( i=0; i < indexassigned && randomindex[i] != RandomNum; i++ );
  468. // if index already assign for symbol, digit, or uppercase letter,
  469. // loop again to try other index.
  470. if( i >= indexassigned )
  471. {
  472. randomindex[indexassigned] = RandomNum;
  473. indexassigned++;
  474. }
  475. }
  476. }
  477. if( ERROR_SUCCESS != dwStatus )
  478. {
  479. goto CLEANUPANDEXIT;
  480. }
  481. dwStatus = ShuffleCharArray(hProv, sizeof(something1), (TCHAR*)&something1);
  482. if( ERROR_SUCCESS != dwStatus )
  483. {
  484. goto CLEANUPANDEXIT;
  485. }
  486. dwStatus = ShuffleCharArray(hProv, sizeof(something2), (TCHAR*)&something2);
  487. if( ERROR_SUCCESS != dwStatus )
  488. {
  489. goto CLEANUPANDEXIT;
  490. }
  491. dwStatus = ShuffleCharArray(hProv, sizeof(something3), (TCHAR*)&something3);
  492. if( ERROR_SUCCESS != dwStatus )
  493. {
  494. goto CLEANUPANDEXIT;
  495. }
  496. dwStatus = ShuffleCharArray(hProv, sizeof(something4), (TCHAR*)&something4);
  497. if( ERROR_SUCCESS != dwStatus )
  498. {
  499. goto CLEANUPANDEXIT;
  500. }
  501. dwStatus = GetRandomNumber(hProv, &RandomNum);
  502. if( ERROR_SUCCESS != dwStatus )
  503. {
  504. goto CLEANUPANDEXIT;
  505. }
  506. iTotal = sizeof(something1) / sizeof(TCHAR);
  507. pszPassword[randomindex[0]] = something1[RandomNum % iTotal];
  508. dwStatus = GetRandomNumber(hProv, &RandomNum);
  509. if( ERROR_SUCCESS != dwStatus )
  510. {
  511. goto CLEANUPANDEXIT;
  512. }
  513. iTotal = sizeof(something2) / sizeof(TCHAR);
  514. pszPassword[randomindex[1]] = something2[RandomNum % iTotal];
  515. dwStatus = GetRandomNumber(hProv, &RandomNum);
  516. if( ERROR_SUCCESS != dwStatus )
  517. {
  518. goto CLEANUPANDEXIT;
  519. }
  520. iTotal = sizeof(something3) / sizeof(TCHAR);
  521. pszPassword[randomindex[2]] = something3[RandomNum % iTotal];
  522. dwStatus = GetRandomNumber(hProv, &RandomNum);
  523. if( ERROR_SUCCESS != dwStatus )
  524. {
  525. goto CLEANUPANDEXIT;
  526. }
  527. iTotal = sizeof(something4) / sizeof(TCHAR);
  528. pszPassword[randomindex[3]] = something4[RandomNum % iTotal];
  529. pszPassword[nLength] = _T('\0');
  530. CLEANUPANDEXIT:
  531. if( NULL != hProv )
  532. {
  533. CryptReleaseContext( hProv, 0 );
  534. }
  535. return dwStatus;
  536. }
  537. //---------------------------------------------------------
  538. DWORD
  539. RenameLocalAccount(
  540. IN LPWSTR pszOrgName,
  541. IN LPWSTR pszNewName
  542. )
  543. /*++
  544. Routine Description:
  545. Parameters:
  546. Returns:
  547. ERROR_SUCCESS or error code.
  548. --*/
  549. {
  550. NET_API_STATUS err;
  551. USER_INFO_0 UserInfo;
  552. UserInfo.usri0_name = pszNewName;
  553. err = NetUserSetInfo(
  554. NULL,
  555. pszOrgName,
  556. 0,
  557. (LPBYTE) &UserInfo,
  558. NULL
  559. );
  560. return err;
  561. }
  562. DWORD
  563. UpdateLocalAccountFullnameAndDesc(
  564. IN LPWSTR pszAccOrgName,
  565. IN LPWSTR pszAccFullName,
  566. IN LPWSTR pszAccDesc
  567. )
  568. /*++
  569. Routine Description:
  570. Update account full name and description.
  571. Parameters:
  572. pszAccName : Account name.
  573. pszAccFullName : new account full name.
  574. pszAccDesc : new account description.
  575. Returns:
  576. ERROR_SUCCESS or error code
  577. --*/
  578. {
  579. LPBYTE pbServer = NULL;
  580. BYTE *pBuffer;
  581. NET_API_STATUS netErr = NERR_Success;
  582. DWORD parm_err;
  583. netErr = NetUserGetInfo(
  584. NULL,
  585. pszAccOrgName,
  586. 3,
  587. &pBuffer
  588. );
  589. if( NERR_Success == netErr )
  590. {
  591. USER_INFO_3 *lpui3 = (USER_INFO_3 *)pBuffer;
  592. lpui3->usri3_comment = pszAccDesc;
  593. lpui3->usri3_full_name = pszAccFullName;
  594. netErr = NetUserSetInfo(
  595. NULL,
  596. pszAccOrgName,
  597. 3,
  598. (PBYTE)lpui3,
  599. &parm_err
  600. );
  601. NetApiBufferFree(pBuffer);
  602. }
  603. return netErr;
  604. }
  605. DWORD
  606. IsLocalAccountEnabled(
  607. IN LPWSTR pszUserName,
  608. IN BOOL* pEnabled
  609. )
  610. /*++
  611. Routine Description:
  612. Check if local account enabled
  613. Parameters:
  614. pszUserName : Name of user account.
  615. pEnabled : Return TRUE is account is enabled, FALSE otherwise.
  616. Returns:
  617. ERROR_SUCCESS or error code.
  618. --*/
  619. {
  620. DWORD dwResult;
  621. NET_API_STATUS err;
  622. LPBYTE pBuffer;
  623. USER_INFO_1 *pUserInfo;
  624. err = NetUserGetInfo(
  625. NULL,
  626. pszUserName,
  627. 1,
  628. &pBuffer
  629. );
  630. if( NERR_Success == err )
  631. {
  632. pUserInfo = (USER_INFO_1 *)pBuffer;
  633. if (pUserInfo != NULL)
  634. {
  635. if( pUserInfo->usri1_flags & UF_ACCOUNTDISABLE )
  636. {
  637. *pEnabled = FALSE;
  638. }
  639. else
  640. {
  641. *pEnabled = TRUE;
  642. }
  643. }
  644. NetApiBufferFree( pBuffer );
  645. }
  646. else if( NERR_UserNotFound == err )
  647. {
  648. *pEnabled = FALSE;
  649. //err = NERR_Success;
  650. }
  651. return err;
  652. }
  653. //---------------------------------------------------------
  654. DWORD
  655. EnableLocalAccount(
  656. IN LPWSTR pszUserName,
  657. IN BOOL bEnable
  658. )
  659. /*++
  660. Routine Description:
  661. Routine to enable/disable a local account.
  662. Parameters:
  663. pszUserName : Name of user account.
  664. bEnable : TRUE if enabling account, FALSE if disabling account.
  665. Returns:
  666. ERROR_SUCCESS or error code.
  667. --*/
  668. {
  669. DWORD dwResult;
  670. NET_API_STATUS err;
  671. LPBYTE pBuffer;
  672. USER_INFO_1 *pUserInfo;
  673. BOOL bChangeAccStatus = TRUE;
  674. err = NetUserGetInfo(
  675. NULL,
  676. pszUserName,
  677. 1,
  678. &pBuffer
  679. );
  680. if( NERR_Success == err )
  681. {
  682. pUserInfo = (USER_INFO_1 *)pBuffer;
  683. if(pUserInfo != NULL)
  684. {
  685. if( TRUE == bEnable && pUserInfo->usri1_flags & UF_ACCOUNTDISABLE )
  686. {
  687. pUserInfo->usri1_flags &= ~UF_ACCOUNTDISABLE;
  688. }
  689. else if( FALSE == bEnable && !(pUserInfo->usri1_flags & UF_ACCOUNTDISABLE) )
  690. {
  691. pUserInfo->usri1_flags |= UF_ACCOUNTDISABLE;
  692. }
  693. else
  694. {
  695. bChangeAccStatus = FALSE;
  696. }
  697. if( TRUE == bChangeAccStatus )
  698. {
  699. err = NetUserSetInfo(
  700. NULL,
  701. pszUserName,
  702. 1,
  703. pBuffer,
  704. &dwResult
  705. );
  706. }
  707. }
  708. NetApiBufferFree( pBuffer );
  709. }
  710. return err;
  711. }
  712. //---------------------------------------------------------
  713. BOOL
  714. IsPersonalOrProMachine()
  715. /*++
  716. Routine Description:
  717. Check if machine is PER or PRO sku.
  718. Parameters:
  719. None.
  720. Return:
  721. TRUE/FALSE
  722. --*/
  723. {
  724. BOOL fRet;
  725. DWORDLONG dwlConditionMask;
  726. OSVERSIONINFOEX osVersionInfo;
  727. RtlZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX));
  728. osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  729. osVersionInfo.wProductType = VER_NT_WORKSTATION;
  730. dwlConditionMask = 0;
  731. VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
  732. fRet = VerifyVersionInfo(
  733. &osVersionInfo,
  734. VER_PRODUCT_TYPE,
  735. dwlConditionMask
  736. );
  737. return fRet;
  738. }
  739. DWORD
  740. CreateLocalAccount(
  741. IN LPWSTR pszUserName,
  742. IN LPWSTR pszUserPwd,
  743. IN LPWSTR pszFullName,
  744. IN LPWSTR pszComment,
  745. IN LPWSTR pszGroup,
  746. IN LPWSTR pszScript,
  747. OUT BOOL* pbAccountExist
  748. )
  749. /*++
  750. Routine Description:
  751. Create an user account on local machine.
  752. Parameters:
  753. pszUserName : Name of the user account.
  754. pszUserPwd : User account password.
  755. pszFullName : Account Full Name.
  756. pszComment : Account comment.
  757. pszGroup : Local group of the account.
  758. pbAccountExist ; Return TRUE if account already exists, FALSE otherwise.
  759. Returns:
  760. ERROR_SUCCESS or error code.
  761. --*/
  762. {
  763. LPBYTE pbServer = NULL;
  764. BYTE *pBuffer;
  765. NET_API_STATUS netErr = NERR_Success;
  766. DWORD parm_err;
  767. DWORD dwStatus;
  768. netErr = NetUserGetInfo(
  769. NULL,
  770. pszUserName,
  771. 3,
  772. &pBuffer
  773. );
  774. if( NERR_Success == netErr )
  775. {
  776. //
  777. // User account exists, if account is disabled,
  778. // enable it and change password
  779. //
  780. USER_INFO_3 *lpui3 = (USER_INFO_3 *)pBuffer;
  781. if( lpui3->usri3_flags & UF_ACCOUNTDISABLE ||
  782. lpui3->usri3_flags & UF_LOCKOUT )
  783. {
  784. // enable the account
  785. lpui3->usri3_flags &= ~ ~UF_LOCKOUT;;
  786. if( lpui3->usri3_flags & UF_ACCOUNTDISABLE )
  787. {
  788. // we only reset password if account is disabled.
  789. lpui3->usri3_flags &= ~ UF_ACCOUNTDISABLE;
  790. }
  791. //lpui3->usri3_password = pszUserPwd;
  792. // reset password if account is disabled.
  793. lpui3->usri3_name = pszUserName;
  794. lpui3->usri3_comment = pszComment;
  795. lpui3->usri3_full_name = pszFullName;
  796. //lpui3->usri3_primary_group_id = dwGroupId;
  797. netErr = NetUserSetInfo(
  798. NULL,
  799. pszUserName,
  800. 3,
  801. (PBYTE)lpui3,
  802. &parm_err
  803. );
  804. }
  805. *pbAccountExist = TRUE;
  806. NetApiBufferFree(pBuffer);
  807. }
  808. else if( NERR_UserNotFound == netErr )
  809. {
  810. //
  811. // Account does not exist, create and set it to our group
  812. //
  813. USER_INFO_1 UserInfo;
  814. memset(&UserInfo, 0, sizeof(USER_INFO_1));
  815. UserInfo.usri1_name = pszUserName;
  816. UserInfo.usri1_password = pszUserPwd;
  817. UserInfo.usri1_priv = USER_PRIV_USER; // see USER_INFO_1 for detail
  818. UserInfo.usri1_comment = pszComment;
  819. UserInfo.usri1_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD;
  820. netErr = NetUserAdd(
  821. NULL,
  822. 1,
  823. (PBYTE)&UserInfo,
  824. &parm_err
  825. );
  826. *pbAccountExist = FALSE;
  827. }
  828. return netErr;
  829. }
  830. ///////////////////////////////////////////////////////////////////////////////
  831. DWORD
  832. ChangeLocalAccountPassword(
  833. IN LPWSTR pszAccName,
  834. IN LPWSTR pszOldPwd,
  835. IN LPWSTR pszNewPwd
  836. )
  837. /*++
  838. Routine Description:
  839. Change password of a local account.
  840. Parameters:
  841. pszAccName : Name of user account.
  842. pszOldPwd : Old password.
  843. pszNewPwd : New password.
  844. Returns:
  845. ERROR_SUCCESS or error code.
  846. Notes:
  847. User NetUserChangePassword(), must have priviledge
  848. --*/
  849. {
  850. USER_INFO_1003 sUserInfo3;
  851. NET_API_STATUS netErr;
  852. UNREFERENCED_PARAMETER( pszOldPwd );
  853. sUserInfo3.usri1003_password = pszNewPwd;
  854. netErr = NetUserSetInfo(
  855. NULL,
  856. pszAccName,
  857. 1003,
  858. (BYTE *) &sUserInfo3,
  859. 0
  860. );
  861. return netErr;
  862. }
  863. ///////////////////////////////////////////////////////////////////////////////
  864. DWORD
  865. RetrieveKeyFromLSA(
  866. IN PWCHAR pwszKeyName,
  867. OUT PBYTE * ppbKey,
  868. OUT DWORD * pcbKey
  869. )
  870. /*++
  871. Routine Description:
  872. Retrieve private data previously stored with StoreKeyWithLSA().
  873. Parameters:
  874. pwszKeyName : Name of the key.
  875. ppbKey : Pointer to PBYTE to receive binary data.
  876. pcbKey : Size of binary data.
  877. Returns:
  878. ERROR_SUCCESS
  879. ERROR_INVALID_PARAMETER.
  880. ERROR_FILE_NOT_FOUND
  881. LSA return code
  882. Note:
  883. Memory is allocated using LocalAlloc()
  884. --*/
  885. {
  886. LSA_HANDLE PolicyHandle;
  887. UNICODE_STRING SecretKeyName;
  888. UNICODE_STRING *pSecretData;
  889. DWORD Status;
  890. if( ( NULL == pwszKeyName ) || ( NULL == ppbKey ) || ( NULL == pcbKey ) )
  891. {
  892. return( ERROR_INVALID_PARAMETER );
  893. }
  894. //
  895. // setup the UNICODE_STRINGs for the call.
  896. //
  897. InitLsaString(
  898. &SecretKeyName,
  899. pwszKeyName
  900. );
  901. Status = OpenPolicy(
  902. NULL,
  903. POLICY_GET_PRIVATE_INFORMATION,
  904. &PolicyHandle
  905. );
  906. if( Status != ERROR_SUCCESS )
  907. {
  908. return LsaNtStatusToWinError(Status);
  909. }
  910. Status = LsaRetrievePrivateData(
  911. PolicyHandle,
  912. &SecretKeyName,
  913. &pSecretData
  914. );
  915. LsaClose( PolicyHandle );
  916. if( Status != ERROR_SUCCESS )
  917. {
  918. return LsaNtStatusToWinError(Status);
  919. }
  920. if(pSecretData->Length)
  921. {
  922. *ppbKey = ( LPBYTE )LocalAlloc( LPTR, pSecretData->Length );
  923. if( *ppbKey )
  924. {
  925. *pcbKey = pSecretData->Length;
  926. CopyMemory( *ppbKey, pSecretData->Buffer, pSecretData->Length );
  927. Status = ERROR_SUCCESS;
  928. }
  929. else
  930. {
  931. Status = GetLastError();
  932. }
  933. }
  934. else
  935. {
  936. Status = ERROR_FILE_NOT_FOUND;
  937. *pcbKey = 0;
  938. *ppbKey = NULL;
  939. }
  940. ZeroMemory( pSecretData->Buffer, pSecretData->Length );
  941. LsaFreeMemory( pSecretData );
  942. return Status;
  943. }
  944. ///////////////////////////////////////////////////////////////////////////////
  945. DWORD
  946. StoreKeyWithLSA(
  947. IN PWCHAR pwszKeyName,
  948. IN BYTE * pbKey,
  949. IN DWORD cbKey
  950. )
  951. /*++
  952. Routine Description:
  953. Save private data to LSA.
  954. Parameters:
  955. pwszKeyName : Name of the key this data going to be stored under.
  956. pbKey : Binary data to be saved, pass NULL to delete previously stored
  957. LSA key and data.
  958. cbKey : Size of binary data.
  959. Returns:
  960. ERROR_SUCCESS
  961. ERROR_INVALID_PARAMETER.
  962. LSA return code
  963. --*/
  964. {
  965. LSA_HANDLE PolicyHandle;
  966. UNICODE_STRING SecretKeyName;
  967. UNICODE_STRING SecretData;
  968. DWORD Status;
  969. if( ( NULL == pwszKeyName ) )
  970. {
  971. return( ERROR_INVALID_PARAMETER );
  972. }
  973. //
  974. // setup the UNICODE_STRINGs for the call.
  975. //
  976. InitLsaString(
  977. &SecretKeyName,
  978. pwszKeyName
  979. );
  980. SecretData.Buffer = ( LPWSTR )pbKey;
  981. SecretData.Length = ( USHORT )cbKey;
  982. SecretData.MaximumLength = ( USHORT )cbKey;
  983. Status = OpenPolicy(
  984. NULL,
  985. POLICY_CREATE_SECRET,
  986. &PolicyHandle
  987. );
  988. if( Status != ERROR_SUCCESS )
  989. {
  990. return LsaNtStatusToWinError(Status);
  991. }
  992. // Based on pbKey, either to store the data or delete the key.
  993. Status = LsaStorePrivateData(
  994. PolicyHandle,
  995. &SecretKeyName,
  996. (pbKey != NULL) ? &SecretData : NULL
  997. );
  998. LsaClose(PolicyHandle);
  999. return LsaNtStatusToWinError(Status);
  1000. }
  1001. ///////////////////////////////////////////////////////////////////////////////
  1002. DWORD
  1003. OpenPolicy(
  1004. IN LPWSTR ServerName,
  1005. IN DWORD DesiredAccess,
  1006. OUT PLSA_HANDLE PolicyHandle
  1007. )
  1008. /*++
  1009. Routine Description:
  1010. Create/return a LSA policy handle.
  1011. Parameters:
  1012. ServerName : Name of server, refer to LsaOpenPolicy().
  1013. DesiredAccess : Desired access level, refer to LsaOpenPolicy().
  1014. PolicyHandle : Return PLSA_HANDLE.
  1015. Returns:
  1016. ERROR_SUCCESS or LSA error code
  1017. --*/
  1018. {
  1019. LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  1020. LSA_UNICODE_STRING ServerString;
  1021. PLSA_UNICODE_STRING Server;
  1022. //
  1023. // Always initialize the object attributes to all zeroes.
  1024. //
  1025. ZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  1026. if( NULL != ServerName )
  1027. {
  1028. //
  1029. // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
  1030. //
  1031. InitLsaString( &ServerString, ServerName );
  1032. Server = &ServerString;
  1033. }
  1034. else
  1035. {
  1036. Server = NULL;
  1037. }
  1038. //
  1039. // Attempt to open the policy.
  1040. //
  1041. return( LsaOpenPolicy(
  1042. Server,
  1043. &ObjectAttributes,
  1044. DesiredAccess,
  1045. PolicyHandle ) );
  1046. }
  1047. ///////////////////////////////////////////////////////////////////////////////
  1048. void
  1049. InitLsaString(
  1050. IN OUT PLSA_UNICODE_STRING LsaString,
  1051. IN LPWSTR String
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. Initialize LSA unicode string.
  1056. Parameters:
  1057. LsaString : Pointer to LSA_UNICODE_STRING to be initialized.
  1058. String : String to initialize LsaString.
  1059. Returns:
  1060. None.
  1061. Note:
  1062. Refer to LSA_UNICODE_STRING
  1063. --*/
  1064. {
  1065. DWORD StringLength;
  1066. if( NULL == String )
  1067. {
  1068. LsaString->Buffer = NULL;
  1069. LsaString->Length = 0;
  1070. LsaString->MaximumLength = 0;
  1071. return;
  1072. }
  1073. StringLength = lstrlenW( String );
  1074. LsaString->Buffer = String;
  1075. LsaString->Length = ( USHORT ) StringLength * sizeof( WCHAR );
  1076. LsaString->MaximumLength=( USHORT )( StringLength + 1 ) * sizeof( WCHAR );
  1077. }
  1078. //-----------------------------------------------------
  1079. BOOL
  1080. ValidatePassword(
  1081. IN LPWSTR pszUserName,
  1082. IN LPWSTR pszDomain,
  1083. IN LPWSTR pszPassword
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. Validate user account password.
  1088. Parameters:
  1089. pszUserName : Name of user account.
  1090. pszDomain : Domain name.
  1091. pszPassword : Password to be verified.
  1092. Returns:
  1093. TRUE or FALSE.
  1094. Note:
  1095. To debug this code, you will need to run process as service in order
  1096. for it to verify password. Refer to MSDN on LogonUser
  1097. --*/
  1098. {
  1099. HANDLE hToken;
  1100. BOOL bSuccess;
  1101. //
  1102. // To debug this code, you will need to run process as service in order
  1103. // for it to verify password. Refer to MSDN on LogonUser
  1104. //
  1105. bSuccess = LogonUser(
  1106. pszUserName,
  1107. pszDomain, //_TEXT("."), //pszDomain,
  1108. pszPassword,
  1109. LOGON32_LOGON_NETWORK_CLEARTEXT,
  1110. LOGON32_PROVIDER_DEFAULT,
  1111. &hToken
  1112. );
  1113. if( TRUE == bSuccess )
  1114. {
  1115. CloseHandle( hToken );
  1116. }
  1117. else
  1118. {
  1119. DWORD dwStatus = GetLastError();
  1120. DebugPrintf(
  1121. _TEXT("ValidatePassword() failed with %d\n"),
  1122. dwStatus
  1123. );
  1124. SetLastError(dwStatus);
  1125. }
  1126. return bSuccess;
  1127. }
  1128. //---------------------------------------------------------------
  1129. BOOL
  1130. GetTextualSid(
  1131. IN PSID pSid, // binary Sid
  1132. IN OUT LPTSTR TextualSid, // buffer for Textual representation of Sid
  1133. IN OUT LPDWORD lpdwBufferLen // required/provided TextualSid buffersize
  1134. )
  1135. /*++
  1136. Routine Description:
  1137. Conver a SID to string representation, code from MSDN
  1138. Parameters:
  1139. pSid : Pointer to SID to be converted to string.
  1140. TextualSid : On input, pointer to buffer to received converted string, on output,
  1141. converted SID in string form.
  1142. lpdwBufferLen : On input, size of the buffer, on output, length of converted string
  1143. or required buffer size in char.
  1144. Returns:
  1145. TRUE/FALSE, use GetLastError() to retrieve detail error code.
  1146. --*/
  1147. {
  1148. PSID_IDENTIFIER_AUTHORITY psia;
  1149. DWORD dwSubAuthorities;
  1150. DWORD dwSidRev=SID_REVISION;
  1151. DWORD dwCounter;
  1152. DWORD dwSidSize;
  1153. // Validate the binary SID.
  1154. if(!IsValidSid(pSid))
  1155. {
  1156. return FALSE;
  1157. }
  1158. // Get the identifier authority value from the SID.
  1159. psia = GetSidIdentifierAuthority(pSid);
  1160. // Get the number of subauthorities in the SID.
  1161. dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
  1162. // Compute the buffer length.
  1163. // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
  1164. dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
  1165. // Check input buffer length.
  1166. // If too small, indicate the proper size and set last error.
  1167. if (*lpdwBufferLen < dwSidSize)
  1168. {
  1169. *lpdwBufferLen = dwSidSize;
  1170. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1171. return FALSE;
  1172. }
  1173. // Add 'S' prefix and revision number to the string.
  1174. dwSidSize=wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev );
  1175. // Add SID identifier authority to the string.
  1176. if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
  1177. {
  1178. dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
  1179. TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
  1180. (USHORT)psia->Value[0],
  1181. (USHORT)psia->Value[1],
  1182. (USHORT)psia->Value[2],
  1183. (USHORT)psia->Value[3],
  1184. (USHORT)psia->Value[4],
  1185. (USHORT)psia->Value[5]);
  1186. }
  1187. else
  1188. {
  1189. dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
  1190. TEXT("%lu"),
  1191. (ULONG)(psia->Value[5] ) +
  1192. (ULONG)(psia->Value[4] << 8) +
  1193. (ULONG)(psia->Value[3] << 16) +
  1194. (ULONG)(psia->Value[2] << 24) );
  1195. }
  1196. // Add SID subauthorities to the string.
  1197. //
  1198. for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
  1199. {
  1200. dwSidSize+=wsprintf(TextualSid + dwSidSize, TEXT("-%lu"),
  1201. *GetSidSubAuthority(pSid, dwCounter) );
  1202. }
  1203. return TRUE;
  1204. }
  1205. long
  1206. GetUserTSLogonIdEx(
  1207. HANDLE hToken
  1208. )
  1209. /*++
  1210. --*/
  1211. {
  1212. BOOL Result;
  1213. LONG SessionId = -1;
  1214. ULONG ReturnLength;
  1215. //
  1216. // Use the _HYDRA_ extension to GetTokenInformation to
  1217. // return the SessionId from the token.
  1218. //
  1219. Result = GetTokenInformation(
  1220. hToken,
  1221. TokenSessionId,
  1222. &SessionId,
  1223. sizeof(SessionId),
  1224. &ReturnLength
  1225. );
  1226. if( !Result ) {
  1227. DWORD dwStatus = GetLastError();
  1228. SessionId = -1;
  1229. }
  1230. return SessionId;
  1231. }
  1232. long
  1233. GetUserTSLogonId()
  1234. /*++
  1235. Routine Description:
  1236. Return client TS Session ID.
  1237. Parameters:
  1238. None.
  1239. Returns:
  1240. Client's TS session ID or 0 if not on TS.
  1241. Note:
  1242. Must have impersonate user first.
  1243. --*/
  1244. {
  1245. LONG lSessionId = -1;
  1246. HANDLE hToken;
  1247. BOOL bSuccess;
  1248. bSuccess = OpenThreadToken(
  1249. GetCurrentThread(),
  1250. TOKEN_QUERY,
  1251. TRUE,
  1252. &hToken
  1253. );
  1254. if( TRUE == bSuccess )
  1255. {
  1256. lSessionId = GetUserTSLogonIdEx(hToken);
  1257. CloseHandle(hToken);
  1258. }
  1259. return lSessionId;
  1260. }
  1261. //
  1262. //
  1263. ////////////////////////////////////////////////////////////////
  1264. //
  1265. //
  1266. DWORD
  1267. RegEnumSubKeys(
  1268. IN HKEY hKey,
  1269. IN LPCTSTR pszSubKey,
  1270. IN RegEnumKeyCallback pFunc,
  1271. IN HANDLE userData
  1272. )
  1273. /*++
  1274. --*/
  1275. {
  1276. DWORD dwStatus;
  1277. HKEY hSubKey = NULL;
  1278. int index;
  1279. LONG dwNumSubKeys;
  1280. DWORD dwMaxSubKeyLength;
  1281. DWORD dwSubKeyLength;
  1282. LPTSTR pszSubKeyName = NULL;
  1283. DWORD dwMaxValueNameLen;
  1284. LPTSTR pszValueName = NULL;
  1285. DWORD dwValueNameLength;
  1286. if( NULL == hKey )
  1287. {
  1288. dwStatus = ERROR_INVALID_PARAMETER;
  1289. return dwStatus;
  1290. }
  1291. dwStatus = RegOpenKeyEx(
  1292. hKey,
  1293. pszSubKey,
  1294. 0,
  1295. KEY_ALL_ACCESS,
  1296. &hSubKey
  1297. );
  1298. if(dwStatus != ERROR_SUCCESS)
  1299. {
  1300. // key does not exist
  1301. return dwStatus;
  1302. }
  1303. //
  1304. // Query number of subkeys
  1305. //
  1306. dwStatus = RegQueryInfoKey(
  1307. hSubKey,
  1308. NULL,
  1309. NULL,
  1310. NULL,
  1311. (DWORD *)&dwNumSubKeys,
  1312. &dwMaxSubKeyLength,
  1313. NULL,
  1314. NULL,
  1315. &dwMaxValueNameLen,
  1316. NULL,
  1317. NULL,
  1318. NULL
  1319. );
  1320. if(dwStatus != ERROR_SUCCESS)
  1321. {
  1322. goto cleanup;
  1323. }
  1324. dwMaxValueNameLen++;
  1325. pszValueName = (LPTSTR)LocalAlloc(
  1326. LPTR,
  1327. dwMaxValueNameLen * sizeof(TCHAR)
  1328. );
  1329. if(pszValueName == NULL)
  1330. {
  1331. dwStatus = ERROR_OUTOFMEMORY;
  1332. goto cleanup;
  1333. }
  1334. if(dwNumSubKeys > 0)
  1335. {
  1336. // allocate buffer for subkeys.
  1337. dwMaxSubKeyLength++;
  1338. pszSubKeyName = (LPTSTR)LocalAlloc(
  1339. LPTR,
  1340. dwMaxSubKeyLength * sizeof(TCHAR)
  1341. );
  1342. if(pszSubKeyName == NULL)
  1343. {
  1344. dwStatus = ERROR_OUTOFMEMORY;
  1345. goto cleanup;
  1346. }
  1347. for(;dwStatus == ERROR_SUCCESS && dwNumSubKeys >= 0;)
  1348. {
  1349. // delete this subkey.
  1350. dwSubKeyLength = dwMaxSubKeyLength;
  1351. memset(pszSubKeyName, 0, dwMaxSubKeyLength * sizeof(TCHAR));
  1352. // retrieve subkey name
  1353. dwStatus = RegEnumKeyEx(
  1354. hSubKey,
  1355. (DWORD)--dwNumSubKeys,
  1356. pszSubKeyName,
  1357. &dwSubKeyLength,
  1358. NULL,
  1359. NULL,
  1360. NULL,
  1361. NULL
  1362. );
  1363. if(dwStatus == ERROR_SUCCESS)
  1364. {
  1365. dwStatus = pFunc(
  1366. hSubKey,
  1367. pszSubKeyName,
  1368. userData
  1369. );
  1370. }
  1371. }
  1372. if( ERROR_NO_MORE_ITEMS == dwStatus )
  1373. {
  1374. dwStatus = ERROR_SUCCESS;
  1375. }
  1376. }
  1377. cleanup:
  1378. // close the key before trying to delete it.
  1379. if(hSubKey != NULL)
  1380. {
  1381. RegCloseKey(hSubKey);
  1382. }
  1383. if(pszValueName != NULL)
  1384. {
  1385. LocalFree(pszValueName);
  1386. }
  1387. if(pszSubKeyName != NULL)
  1388. {
  1389. LocalFree(pszSubKeyName);
  1390. }
  1391. return dwStatus;
  1392. }
  1393. DWORD
  1394. RegDelKey(
  1395. IN HKEY hRegKey,
  1396. IN LPCTSTR pszSubKey
  1397. )
  1398. /*++
  1399. Abstract:
  1400. Recursively delete entire registry key.
  1401. Parameter:
  1402. hKey : Handle to a curently open key.
  1403. pszSubKey : Pointer to NULL terminated string containing the key to be deleted.
  1404. Returns:
  1405. Error code from RegOpenKeyEx(), RegQueryInfoKey(),
  1406. RegEnumKeyEx().
  1407. ++*/
  1408. {
  1409. DWORD dwStatus;
  1410. HKEY hSubKey = NULL;
  1411. int index;
  1412. DWORD dwNumSubKeys;
  1413. DWORD dwMaxSubKeyLength;
  1414. DWORD dwSubKeyLength;
  1415. LPTSTR pszSubKeyName = NULL;
  1416. DWORD dwMaxValueNameLen;
  1417. LPTSTR pszValueName = NULL;
  1418. DWORD dwValueNameLength;
  1419. if( NULL == hRegKey )
  1420. {
  1421. dwStatus = ERROR_INVALID_PARAMETER;
  1422. return dwStatus;
  1423. }
  1424. dwStatus = RegOpenKeyEx(
  1425. hRegKey,
  1426. pszSubKey,
  1427. 0,
  1428. KEY_ALL_ACCESS,
  1429. &hSubKey
  1430. );
  1431. if(dwStatus != ERROR_SUCCESS)
  1432. {
  1433. // key does not exist
  1434. return dwStatus;
  1435. }
  1436. //
  1437. // Query number of subkeys
  1438. //
  1439. dwStatus = RegQueryInfoKey(
  1440. hSubKey,
  1441. NULL,
  1442. NULL,
  1443. NULL,
  1444. &dwNumSubKeys,
  1445. &dwMaxSubKeyLength,
  1446. NULL,
  1447. NULL,
  1448. &dwMaxValueNameLen,
  1449. NULL,
  1450. NULL,
  1451. NULL
  1452. );
  1453. if(dwStatus != ERROR_SUCCESS)
  1454. {
  1455. goto cleanup;
  1456. }
  1457. dwMaxValueNameLen++;
  1458. pszValueName = (LPTSTR)LocalAlloc(
  1459. LPTR,
  1460. dwMaxValueNameLen * sizeof(TCHAR)
  1461. );
  1462. if(pszValueName == NULL)
  1463. {
  1464. dwStatus = ERROR_OUTOFMEMORY;
  1465. goto cleanup;
  1466. }
  1467. if(dwNumSubKeys > 0)
  1468. {
  1469. // allocate buffer for subkeys.
  1470. dwMaxSubKeyLength++;
  1471. pszSubKeyName = (LPTSTR)LocalAlloc(
  1472. LPTR,
  1473. dwMaxSubKeyLength * sizeof(TCHAR)
  1474. );
  1475. if(pszSubKeyName == NULL)
  1476. {
  1477. dwStatus = ERROR_OUTOFMEMORY;
  1478. goto cleanup;
  1479. }
  1480. //for(index = 0; index < dwNumSubKeys; index++)
  1481. for(;dwStatus == ERROR_SUCCESS;)
  1482. {
  1483. // delete this subkey.
  1484. dwSubKeyLength = dwMaxSubKeyLength;
  1485. memset(pszSubKeyName, 0, dwMaxSubKeyLength * sizeof(TCHAR));
  1486. // retrieve subkey name
  1487. dwStatus = RegEnumKeyEx(
  1488. hSubKey,
  1489. (DWORD)0,
  1490. pszSubKeyName,
  1491. &dwSubKeyLength,
  1492. NULL,
  1493. NULL,
  1494. NULL,
  1495. NULL
  1496. );
  1497. if(dwStatus == ERROR_SUCCESS)
  1498. {
  1499. dwStatus = RegDelKey( hSubKey, pszSubKeyName );
  1500. }
  1501. }
  1502. }
  1503. cleanup:
  1504. for(dwStatus = ERROR_SUCCESS; pszValueName != NULL && dwStatus == ERROR_SUCCESS;)
  1505. {
  1506. dwValueNameLength = dwMaxValueNameLen;
  1507. memset(pszValueName, 0, dwMaxValueNameLen * sizeof(TCHAR));
  1508. dwStatus = RegEnumValue(
  1509. hSubKey,
  1510. 0,
  1511. pszValueName,
  1512. &dwValueNameLength,
  1513. NULL,
  1514. NULL,
  1515. NULL,
  1516. NULL
  1517. );
  1518. if(dwStatus == ERROR_SUCCESS)
  1519. {
  1520. RegDeleteValue(hSubKey, pszValueName);
  1521. }
  1522. }
  1523. // close the key before trying to delete it.
  1524. if(hSubKey != NULL)
  1525. {
  1526. RegCloseKey(hSubKey);
  1527. }
  1528. // try to delete this key, will fail if any of the subkey
  1529. // failed to delete in loop
  1530. dwStatus = RegDeleteKey(
  1531. hRegKey,
  1532. pszSubKey
  1533. );
  1534. if(pszValueName != NULL)
  1535. {
  1536. LocalFree(pszValueName);
  1537. }
  1538. if(pszSubKeyName != NULL)
  1539. {
  1540. LocalFree(pszSubKeyName);
  1541. }
  1542. return dwStatus;
  1543. }
  1544. //---------------------------------------------------------------
  1545. DWORD
  1546. GetUserSid(
  1547. OUT PBYTE* ppbSid,
  1548. OUT DWORD* pcbSid
  1549. )
  1550. /*++
  1551. Routine Description:
  1552. Retrieve user's SID , must impersonate client first.
  1553. Parameters:
  1554. ppbSid : Pointer to PBYTE to receive user's SID.
  1555. pcbSid : Pointer to DWORD to receive size of SID.
  1556. Returns:
  1557. ERROR_SUCCESS or error code.
  1558. Note:
  1559. Must have call ImpersonateClient(), funtion is NT specific,
  1560. Win9X will return internal error.
  1561. --*/
  1562. {
  1563. BOOL bSuccess = TRUE;
  1564. DWORD dwStatus = ERROR_SUCCESS;
  1565. HANDLE hToken = NULL;
  1566. DWORD dwSize = 0;
  1567. TOKEN_USER* pToken = NULL;
  1568. *ppbSid = NULL;
  1569. *pcbSid = 0;
  1570. //
  1571. // Open current process token
  1572. //
  1573. bSuccess = OpenThreadToken(
  1574. GetCurrentThread(),
  1575. TOKEN_QUERY,
  1576. TRUE,
  1577. &hToken
  1578. );
  1579. if( TRUE == bSuccess )
  1580. {
  1581. //
  1582. // get user's token.
  1583. //
  1584. GetTokenInformation(
  1585. hToken,
  1586. TokenUser,
  1587. NULL,
  1588. 0,
  1589. &dwSize
  1590. );
  1591. pToken = (TOKEN_USER *)LocalAlloc( LPTR, dwSize );
  1592. if( NULL != pToken )
  1593. {
  1594. bSuccess = GetTokenInformation(
  1595. hToken,
  1596. TokenUser,
  1597. (LPVOID) pToken,
  1598. dwSize,
  1599. &dwSize
  1600. );
  1601. if( TRUE == bSuccess )
  1602. {
  1603. //
  1604. // GetLengthSid() return size of buffer require,
  1605. // must call IsValidSid() first
  1606. //
  1607. bSuccess = IsValidSid( pToken->User.Sid );
  1608. if( TRUE == bSuccess )
  1609. {
  1610. *pcbSid = GetLengthSid( (PBYTE)pToken->User.Sid );
  1611. *ppbSid = (PBYTE)LocalAlloc(LPTR, *pcbSid);
  1612. if( NULL != *ppbSid )
  1613. {
  1614. bSuccess = CopySid(
  1615. *pcbSid,
  1616. *ppbSid,
  1617. pToken->User.Sid
  1618. );
  1619. }
  1620. else // fail in LocalAlloc()
  1621. {
  1622. bSuccess = FALSE;
  1623. }
  1624. } // IsValidSid()
  1625. } // GetTokenInformation()
  1626. }
  1627. else // LocalAlloc() fail
  1628. {
  1629. bSuccess = FALSE;
  1630. }
  1631. }
  1632. if( TRUE != bSuccess )
  1633. {
  1634. dwStatus = GetLastError();
  1635. if( NULL != *ppbSid )
  1636. {
  1637. LocalFree(*ppbSid);
  1638. *ppbSid = NULL;
  1639. *pcbSid = 0;
  1640. }
  1641. }
  1642. //
  1643. // Free resources...
  1644. //
  1645. if( NULL != pToken )
  1646. {
  1647. LocalFree(pToken);
  1648. }
  1649. if( NULL != hToken )
  1650. {
  1651. CloseHandle(hToken);
  1652. }
  1653. return dwStatus;
  1654. }
  1655. //----------------------------------------------------------------
  1656. HRESULT
  1657. GetUserSidString(
  1658. OUT CComBSTR& bstrSid
  1659. )
  1660. /*++
  1661. Routine Description:
  1662. Retrieve user's SID in textual form, must impersonate client first.
  1663. Parameters:
  1664. bstrSID : Return users' SID in textual form.
  1665. Returns:
  1666. ERROR_SUCCESS or error code.
  1667. Note:
  1668. Must have call ImpersonateClient().
  1669. --*/
  1670. {
  1671. DWORD dwStatus;
  1672. PBYTE pbSid = NULL;
  1673. DWORD cbSid = 0;
  1674. BOOL bSuccess = TRUE;
  1675. LPTSTR pszTextualSid = NULL;
  1676. DWORD dwTextualSid = 0;
  1677. dwStatus = GetUserSid( &pbSid, &cbSid );
  1678. if( ERROR_SUCCESS == dwStatus )
  1679. {
  1680. bSuccess = GetTextualSid(
  1681. pbSid,
  1682. NULL,
  1683. &dwTextualSid
  1684. );
  1685. if( FALSE == bSuccess && ERROR_INSUFFICIENT_BUFFER == GetLastError() )
  1686. {
  1687. pszTextualSid = (LPTSTR)LocalAlloc(
  1688. LPTR,
  1689. (dwTextualSid + 1) * sizeof(TCHAR)
  1690. );
  1691. if( NULL != pszTextualSid )
  1692. {
  1693. bSuccess = GetTextualSid(
  1694. pbSid,
  1695. pszTextualSid,
  1696. &dwTextualSid
  1697. );
  1698. if( TRUE == bSuccess )
  1699. {
  1700. bstrSid = pszTextualSid;
  1701. }
  1702. }
  1703. }
  1704. if( FALSE == bSuccess )
  1705. {
  1706. dwStatus = GetLastError();
  1707. }
  1708. }
  1709. if( NULL != pszTextualSid )
  1710. {
  1711. LocalFree(pszTextualSid);
  1712. }
  1713. if( NULL != pbSid )
  1714. {
  1715. LocalFree(pbSid);
  1716. }
  1717. return HRESULT_FROM_WIN32(dwStatus);
  1718. }
  1719. HRESULT
  1720. ConvertSidToAccountName(
  1721. IN CComBSTR& SidString,
  1722. IN BSTR* ppszDomain,
  1723. IN BSTR* ppszUserAcc
  1724. )
  1725. /*++
  1726. Description:
  1727. Convert a string SID to domain\account.
  1728. Parameters:
  1729. ownerSidString : SID in string form to be converted.
  1730. ppszDomain : Pointer to string pointer to receive domain name
  1731. UserAcc : Pointer to string pointer to receive user name
  1732. Returns:
  1733. S_OK or error code.
  1734. Note:
  1735. Routine uses LocalAlloc() to allocate memory for ppszDomain
  1736. and ppszUserAcc.
  1737. --*/
  1738. {
  1739. DWORD dwStatus = ERROR_SUCCESS;
  1740. PSID pOwnerSid = NULL;
  1741. //LPTSTR pszAccName = NULL;
  1742. BSTR pszAccName = NULL;
  1743. DWORD cbAccName = 0;
  1744. //LPTSTR pszDomainName = NULL;
  1745. BSTR pszDomainName = NULL;
  1746. DWORD cbDomainName = 0;
  1747. SID_NAME_USE SidType;
  1748. BOOL bSuccess;
  1749. //
  1750. // Convert string form SID to PSID
  1751. //
  1752. if( FALSE == ConvertStringSidToSid( (LPCTSTR)SidString, &pOwnerSid ) )
  1753. {
  1754. // this might also fail if system is in shutdown state.
  1755. dwStatus = GetLastError();
  1756. goto CLEANUPANDEXIT;
  1757. }
  1758. if( NULL == ppszDomain || NULL == ppszUserAcc )
  1759. {
  1760. dwStatus = ERROR_INVALID_PARAMETER;
  1761. MYASSERT( FALSE );
  1762. goto CLEANUPANDEXIT;
  1763. }
  1764. //
  1765. // Lookup user account for this SID
  1766. //
  1767. bSuccess = LookupAccountSid(
  1768. NULL,
  1769. pOwnerSid,
  1770. pszAccName,
  1771. &cbAccName,
  1772. pszDomainName,
  1773. &cbDomainName,
  1774. &SidType
  1775. );
  1776. if( TRUE == bSuccess || ERROR_INSUFFICIENT_BUFFER == GetLastError() )
  1777. {
  1778. //pszAccName = (LPWSTR) LocalAlloc( LPTR, (cbAccName + 1) * sizeof(WCHAR) );
  1779. //pszDomainName = (LPWSTR) LocalAlloc( LPTR, (cbDomainName + 1)* sizeof(WCHAR) );
  1780. pszAccName = ::SysAllocStringLen( NULL, (cbAccName + 1) );
  1781. pszDomainName = ::SysAllocStringLen( NULL, (cbDomainName + 1) );
  1782. if( NULL != pszAccName && NULL != pszDomainName )
  1783. {
  1784. bSuccess = LookupAccountSid(
  1785. NULL,
  1786. pOwnerSid,
  1787. pszAccName,
  1788. &cbAccName,
  1789. pszDomainName,
  1790. &cbDomainName,
  1791. &SidType
  1792. );
  1793. }
  1794. else
  1795. {
  1796. SetLastError(ERROR_OUTOFMEMORY);
  1797. bSuccess = FALSE;
  1798. }
  1799. }
  1800. if( FALSE == bSuccess )
  1801. {
  1802. dwStatus = GetLastError();
  1803. }
  1804. else
  1805. {
  1806. *ppszDomain = pszDomainName;
  1807. *ppszUserAcc = pszAccName;
  1808. pszDomainName = NULL;
  1809. pszAccName = NULL;
  1810. }
  1811. CLEANUPANDEXIT:
  1812. if( NULL != pOwnerSid )
  1813. {
  1814. LocalFree( pOwnerSid );
  1815. }
  1816. if( NULL != pszAccName )
  1817. {
  1818. //LocalFree( pszAccName );
  1819. ::SysFreeString( pszAccName );
  1820. }
  1821. if( NULL != pszDomainName )
  1822. {
  1823. // LocalFree( pszDomainName );
  1824. ::SysFreeString( pszAccName );
  1825. }
  1826. return HRESULT_FROM_WIN32(dwStatus);
  1827. }