Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

667 lines
18 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. /* File: utils.cpp
  3. Description: Contains any general utility functions applicable to the
  4. dskquota project.
  5. Revision History:
  6. Date Description Programmer
  7. -------- --------------------------------------------------- ----------
  8. 08/06/96 Initial creation. BrianAu
  9. */
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "pch.h" // PCH
  12. #pragma hdrstop
  13. #include "resource.h"
  14. #include "dskquota.h"
  15. #include <advpub.h> // For REGINSTALL
  16. //
  17. // Verify that build is UNICODE.
  18. //
  19. #if !defined(UNICODE)
  20. # error This module must be compiled UNICODE.
  21. #endif
  22. ///////////////////////////////////////////////////////////////////////////////
  23. /* Function: SidToString
  24. Description: Format a SID as a character string suitable for character
  25. output. This code was taken from MSDN KB article Q131320.
  26. Arguments:
  27. pSid - Address of SID to format.
  28. pszSid - Address of output buffer for formatted SID.
  29. Returns:
  30. TRUE - Success.
  31. FALSE - Destination buffer too small, invalid SID or pSid == NULL.
  32. Revision History:
  33. Date Description Programmer
  34. -------- --------------------------------------------------- ----------
  35. 07/07/96 Initial creation. BrianAu
  36. */
  37. ///////////////////////////////////////////////////////////////////////////////
  38. BOOL SidToString(
  39. PSID pSid,
  40. LPTSTR pszSid,
  41. LPDWORD pcchBuffer
  42. )
  43. {
  44. PSID_IDENTIFIER_AUTHORITY psia;
  45. DWORD dwSubAuthorities;
  46. DWORD dwSidRev=SID_REVISION;
  47. DWORD dwCounter;
  48. DWORD cchSid;
  49. //
  50. // test if Sid passed in is valid
  51. //
  52. if(NULL == pSid || !IsValidSid(pSid))
  53. return FALSE;
  54. // obtain SidIdentifierAuthority
  55. psia = GetSidIdentifierAuthority(pSid);
  56. // obtain sidsubauthority count
  57. dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
  58. //
  59. // compute buffer length
  60. // S-SID_REVISION- + identifierauthority- + subauthorities- + NULL
  61. //
  62. cchSid = (15 + 12 + (12 * dwSubAuthorities) + 1);
  63. //
  64. // check provided buffer length.
  65. // If not large enough, indicate proper size and setlasterror
  66. //
  67. if (*pcchBuffer < cchSid)
  68. {
  69. *pcchBuffer = cchSid;
  70. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  71. return FALSE;
  72. }
  73. //
  74. // prepare S-SID_REVISION-
  75. //
  76. cchSid = wsprintf(pszSid, TEXT("S-%lu-"), dwSidRev );
  77. //
  78. // prepare SidIdentifierAuthority
  79. //
  80. if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
  81. {
  82. cchSid += wsprintf(pszSid + lstrlen(pszSid),
  83. TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
  84. (USHORT)psia->Value[0],
  85. (USHORT)psia->Value[1],
  86. (USHORT)psia->Value[2],
  87. (USHORT)psia->Value[3],
  88. (USHORT)psia->Value[4],
  89. (USHORT)psia->Value[5]);
  90. }
  91. else
  92. {
  93. cchSid += wsprintf(pszSid + lstrlen(pszSid),
  94. TEXT("%lu"),
  95. (ULONG)(psia->Value[5] ) +
  96. (ULONG)(psia->Value[4] << 8) +
  97. (ULONG)(psia->Value[3] << 16) +
  98. (ULONG)(psia->Value[2] << 24) );
  99. }
  100. //
  101. // loop through SidSubAuthorities
  102. //
  103. for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
  104. {
  105. cchSid += wsprintf(pszSid + cchSid, TEXT("-%lu"),
  106. *GetSidSubAuthority(pSid, dwCounter) );
  107. }
  108. return TRUE;
  109. }
  110. ///////////////////////////////////////////////////////////////////////////////
  111. /* Function: SidToString
  112. Description: Format a SID as a character string suitable for character
  113. output. Allocates the destination buffer so that the caller must free
  114. it when done with it.
  115. Arguments:
  116. pSid - Address of SID to format.
  117. ppszSid - Address of LPTSTR variable to receive address of formatted
  118. SID string. If the function returns TRUE, the caller must free
  119. this memory when done with it.
  120. Returns:
  121. TRUE - Success.
  122. FALSE - Destination buffer too small, invalid SID or pSid == NULL.
  123. Revision History:
  124. Date Description Programmer
  125. -------- --------------------------------------------------- ----------
  126. 07/07/96 Initial creation. BrianAu
  127. */
  128. ///////////////////////////////////////////////////////////////////////////////
  129. BOOL SidToString(
  130. PSID pSid,
  131. LPTSTR *ppszSid
  132. )
  133. {
  134. DWORD cchSid = 0;
  135. //
  136. // Call once to get required buffer size.
  137. //
  138. SidToString(pSid, *ppszSid, &cchSid);
  139. *ppszSid = new TCHAR[cchSid];
  140. return SidToString(pSid, *ppszSid, &cchSid);
  141. }
  142. ///////////////////////////////////////////////////////////////////////////////
  143. /* Function: CreateSidList
  144. Description: Creates a structure required for the SID list argument to
  145. NtQueryQuotaInformationFile. The caller passes the address of an
  146. array of SID pointers. The function allocates an sufficient array
  147. and creates the following formatted structure:
  148. +--------+--------+--------+--------+--------+--------+-+
  149. | SID[0] | SID[1] | SID[2] | | |SID[n-1]|0|
  150. +--------+--------+--------+--------+--------+--------+-+
  151. | |
  152. | |
  153. / \
  154. / -------------------------------
  155. / \
  156. / \
  157. +------------+------------+-----------------------------+
  158. | Next entry | SID length | SID |
  159. | offset | (DWORD) | (variable length) |
  160. | (DWORD) | | |
  161. +------------+------------+-----------------------------+
  162. Arguments:
  163. rgpSids - Array of SID pointers.
  164. cpSids - Number of pointers in rgpSids. If 0, the array must
  165. contain a terminating NULL pointer.
  166. ppSidList - Address of a PSIDLIST pointer variable to receive
  167. the address of the final structure. The caller is reponsible
  168. for deleting the returned buffer using "delete".
  169. pcbSidList - Address of DWORD varible to receive the byte count
  170. for the returned SidList structure. If the function returns
  171. hresult ERROR_INVALID_SID, the index in the source array of the invalid
  172. SID will be returned at this location.
  173. Returns:
  174. NO_ERROR - Success.
  175. ERROR_INVALID_SID (hr) - An invalid SID was found in rgpSids. The
  176. index of the invalid SID is returned in *pcbSidList.
  177. Exceptions: OutOfMemory.
  178. Revision History:
  179. Date Description Programmer
  180. -------- --------------------------------------------------- ----------
  181. 08/13/96 Initial creation. BrianAu
  182. 09/05/96 Added exception handling. BrianAu
  183. */
  184. ///////////////////////////////////////////////////////////////////////////////
  185. HRESULT
  186. CreateSidList(
  187. PSID *rgpSids,
  188. DWORD cpSids,
  189. PSIDLIST *ppSidList,
  190. LPDWORD pcbSidList
  191. )
  192. {
  193. HRESULT hResult = NO_ERROR;
  194. DBGASSERT((NULL != rgpSids));
  195. DBGASSERT((NULL != ppSidList));
  196. DBGASSERT((NULL != pcbSidList));
  197. DWORD cbBuffer = 0;
  198. PBYTE pbBuffer = NULL;
  199. //
  200. // Initialize return values.
  201. //
  202. *ppSidList = NULL;
  203. *pcbSidList = 0;
  204. //
  205. // If caller passed 0 for cpSids, list is NULL-terminated.
  206. // Set cpSids to a large value so it is not a factor in controlling the
  207. // byte-counter loop.
  208. //
  209. if (0 == cpSids)
  210. cpSids = (DWORD)~0;
  211. //
  212. // Count how many bytes we'll need to create the SID list.
  213. // Note that a NULL SID pointer at any array location
  214. // will truncate all following SIDs from the final list. Just like strncpy
  215. // with character strings.
  216. //
  217. for (UINT i = 0; NULL != rgpSids[i] && i < cpSids; i++)
  218. {
  219. if (IsValidSid(rgpSids[i]))
  220. {
  221. cbBuffer += (sizeof(DWORD) + sizeof(DWORD) + GetLengthSid(rgpSids[i]));
  222. }
  223. else
  224. {
  225. //
  226. // Tell caller they passed a ptr to an invalid SID and also tell them
  227. // which one it was.
  228. //
  229. hResult = HRESULT_FROM_WIN32(ERROR_INVALID_SID);
  230. *pcbSidList = i;
  231. break;
  232. }
  233. }
  234. //
  235. // Reset cpSids to the actual number of SIDs processed.
  236. //
  237. cpSids = i;
  238. if (SUCCEEDED(hResult))
  239. {
  240. //
  241. // Got a good byte count and all SIDs are valid.
  242. //
  243. DBGASSERT((0 < cpSids));
  244. pbBuffer = new BYTE [cbBuffer]; // Can throw OutOfMemory.
  245. PFILE_GET_QUOTA_INFORMATION pfgqi = NULL;
  246. DWORD cbRecord = 0;
  247. DWORD cbSid = 0;
  248. //
  249. // Return buffer address and length to caller.
  250. //
  251. *ppSidList = (PSIDLIST)pbBuffer;
  252. *pcbSidList = cbBuffer;
  253. for (UINT i = 0; i < cpSids; i++)
  254. {
  255. pfgqi = (PFILE_GET_QUOTA_INFORMATION)pbBuffer;
  256. DBGASSERT((0 == ((DWORD_PTR)pfgqi & 3))); // record is DWORD aligned?
  257. //
  258. // Calculate offsets and sizes for this entry.
  259. //
  260. cbSid = GetLengthSid(rgpSids[i]);
  261. cbRecord = sizeof(pfgqi->NextEntryOffset) +
  262. sizeof(pfgqi->SidLength) +
  263. cbSid;
  264. //
  265. // Write the entry information.
  266. // On last entry, NextEntryOffset is 0.
  267. //
  268. if (i < (cpSids - 1))
  269. pfgqi->NextEntryOffset = cbBuffer + cbRecord;
  270. else
  271. pfgqi->NextEntryOffset = 0;
  272. pfgqi->SidLength = cbSid;
  273. CopyMemory(&(pfgqi->Sid), rgpSids[i], cbSid);
  274. pbBuffer += cbRecord; // Advance write buffer pointer.
  275. }
  276. }
  277. return hResult;
  278. }
  279. ///////////////////////////////////////////////////////////////////////////////
  280. /* Function: MessageBoxNYI
  281. Description: Simple message box for unimplemented features.
  282. Arguments: None.
  283. Returns: Nothing.
  284. Revision History:
  285. Date Description Programmer
  286. -------- --------------------------------------------------- ----------
  287. 08/30/96 Initial creation. BrianAu
  288. */
  289. ///////////////////////////////////////////////////////////////////////////////
  290. VOID MessageBoxNYI(VOID)
  291. {
  292. MessageBox(NULL,
  293. TEXT("This feature has not been implemented."),
  294. TEXT("Under Construction"),
  295. MB_ICONWARNING | MB_OK);
  296. }
  297. ///////////////////////////////////////////////////////////////////////////////
  298. /* Function: DiskQuotaMsgBox
  299. Description: Several overloaded functions for displaying messages.
  300. The variations allow the caller to provide either string resource
  301. IDs or text strings as arguments.
  302. Arguments:
  303. Returns: Nothing.
  304. Revision History:
  305. Date Description Programmer
  306. -------- --------------------------------------------------- ----------
  307. 08/30/96 Initial creation. BrianAu
  308. */
  309. ///////////////////////////////////////////////////////////////////////////////
  310. INT DiskQuotaMsgBox(
  311. HWND hWndParent,
  312. UINT idMsgText,
  313. UINT idMsgTitle,
  314. UINT uType
  315. )
  316. {
  317. INT iReturn = 0;
  318. CString strTitle(g_hInstDll, idMsgTitle);
  319. CString strText(g_hInstDll, idMsgText);
  320. iReturn = MessageBox(hWndParent, strText, strTitle, MB_SETFOREGROUND | uType);
  321. return iReturn;
  322. }
  323. INT DiskQuotaMsgBox(
  324. HWND hWndParent,
  325. LPCTSTR pszText,
  326. LPCTSTR pszTitle,
  327. UINT uType
  328. )
  329. {
  330. return MessageBox(hWndParent, pszText, pszTitle, MB_SETFOREGROUND | uType);
  331. }
  332. INT DiskQuotaMsgBox(
  333. HWND hWndParent,
  334. UINT idMsgText,
  335. LPCTSTR pszTitle,
  336. UINT uType
  337. )
  338. {
  339. INT iReturn = 0;
  340. CString strText(g_hInstDll, idMsgText);
  341. iReturn = MessageBox(hWndParent, strText, pszTitle, MB_SETFOREGROUND | uType);
  342. return iReturn;
  343. }
  344. INT DiskQuotaMsgBox(
  345. HWND hWndParent,
  346. LPCTSTR pszText,
  347. UINT idMsgTitle,
  348. UINT uType
  349. )
  350. {
  351. LPTSTR pszTitle = NULL;
  352. INT iReturn = 0;
  353. CString strTitle(g_hInstDll, idMsgTitle);
  354. iReturn = MessageBox(hWndParent, pszText, strTitle, MB_SETFOREGROUND | uType);
  355. return iReturn;
  356. }
  357. //
  358. // Center a popup window in it's parent.
  359. // If hwndParent is NULL, the window's parent is used.
  360. // If hwndParent is not NULL, hwnd is centered in it.
  361. // If hwndParent is NULL and hwnd doesn't have a parent, it is centered
  362. // on the desktop.
  363. //
  364. VOID
  365. CenterPopupWindow(
  366. HWND hwnd,
  367. HWND hwndParent
  368. )
  369. {
  370. RECT rcScreen;
  371. if (NULL != hwnd)
  372. {
  373. rcScreen.left = rcScreen.top = 0;
  374. rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
  375. rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
  376. if (NULL == hwndParent)
  377. {
  378. hwndParent = GetParent(hwnd);
  379. if (NULL == hwndParent)
  380. hwndParent = GetDesktopWindow();
  381. }
  382. RECT rcWnd;
  383. RECT rcParent;
  384. GetWindowRect(hwnd, &rcWnd);
  385. GetWindowRect(hwndParent, &rcParent);
  386. INT cxWnd = rcWnd.right - rcWnd.left;
  387. INT cyWnd = rcWnd.bottom - rcWnd.top;
  388. INT cxParent = rcParent.right - rcParent.left;
  389. INT cyParent = rcParent.bottom - rcParent.top;
  390. POINT ptParentCtr;
  391. ptParentCtr.x = rcParent.left + (cxParent / 2);
  392. ptParentCtr.y = rcParent.top + (cyParent / 2);
  393. if ((ptParentCtr.x + (cxWnd / 2)) > rcScreen.right)
  394. {
  395. //
  396. // Window would run off the right edge of the screen.
  397. //
  398. rcWnd.left = rcScreen.right - cxWnd;
  399. }
  400. else if ((ptParentCtr.x - (cxWnd / 2)) < rcScreen.left)
  401. {
  402. //
  403. // Window would run off the left edge of the screen.
  404. //
  405. rcWnd.left = rcScreen.left;
  406. }
  407. else
  408. {
  409. rcWnd.left = ptParentCtr.x - (cxWnd / 2);
  410. }
  411. if ((ptParentCtr.y + (cyWnd / 2)) > rcScreen.bottom)
  412. {
  413. //
  414. // Window would run off the bottom edge of the screen.
  415. //
  416. rcWnd.top = rcScreen.bottom - cyWnd;
  417. }
  418. else if ((ptParentCtr.y - (cyWnd / 2)) < rcScreen.top)
  419. {
  420. //
  421. // Window would run off the top edge of the screen.
  422. //
  423. rcWnd.top = rcScreen.top;
  424. }
  425. else
  426. {
  427. rcWnd.top = ptParentCtr.y - (cyWnd / 2);
  428. }
  429. MoveWindow(hwnd, rcWnd.left, rcWnd.top, cxWnd, cyWnd, TRUE);
  430. }
  431. }
  432. //
  433. // Duplicate a string.
  434. //
  435. LPTSTR StringDup(
  436. LPCTSTR pszSource
  437. )
  438. {
  439. LPTSTR pszNew = new TCHAR[lstrlen(pszSource) + 1];
  440. lstrcpy(pszNew, pszSource);
  441. return pszNew;
  442. }
  443. //
  444. // Duplicate a SID.
  445. //
  446. PSID SidDup(
  447. PSID pSid
  448. )
  449. {
  450. DBGASSERT((IsValidSid(pSid)));
  451. DWORD cbSid = GetLengthSid(pSid);
  452. PSID pCopy = new BYTE [cbSid];
  453. CopySid(cbSid, pCopy, pSid);
  454. return pCopy;
  455. }
  456. //
  457. // Similar to Win32's GetDlgItemText except that this one
  458. // doesn't require you to anticipate the required size of the buffer.
  459. //
  460. void
  461. GetDialogItemText(
  462. HWND hwnd,
  463. UINT idCtl,
  464. CString *pstrText
  465. )
  466. {
  467. DBGASSERT((NULL != pstrText));
  468. HWND hwndCtl = GetDlgItem(hwnd, idCtl);
  469. if (NULL != hwndCtl)
  470. {
  471. int cch = (int)SendMessage(hwndCtl, WM_GETTEXTLENGTH, 0, 0) + 1;
  472. SendMessage(hwndCtl, WM_GETTEXT, (WPARAM)cch, (LPARAM)pstrText->GetBuffer(cch));
  473. pstrText->ReleaseBuffer();
  474. }
  475. }
  476. BOOL
  477. UserIsAdministrator(
  478. PDISKQUOTA_USER pUser
  479. )
  480. {
  481. DBGASSERT((NULL != pUser));
  482. BYTE Sid[MAX_SID_LEN];
  483. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  484. PSID pAdminSid = NULL;
  485. BOOL bResult = FALSE;
  486. if (AllocateAndInitializeSid(&sia,
  487. 2,
  488. SECURITY_BUILTIN_DOMAIN_RID,
  489. DOMAIN_ALIAS_RID_ADMINS,
  490. 0, 0, 0, 0, 0, 0,
  491. &pAdminSid))
  492. {
  493. if (SUCCEEDED(pUser->GetSid(Sid, sizeof(Sid))))
  494. {
  495. bResult = EqualSid(Sid, pAdminSid);
  496. }
  497. FreeSid(pAdminSid);
  498. }
  499. return bResult;
  500. }
  501. //
  502. // Call ADVPACK for the given section of our resource based INF.
  503. //
  504. // hInstance - Resource instance containing REGINST section.
  505. // pszSection - Name of section to invoke.
  506. //
  507. HRESULT
  508. CallRegInstall(
  509. HINSTANCE hInstance,
  510. LPSTR pszSection
  511. )
  512. {
  513. HRESULT hr = E_FAIL;
  514. HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL"));
  515. if (hinstAdvPack)
  516. {
  517. REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, "RegInstall");
  518. #ifdef UNICODE
  519. if ( pfnri )
  520. {
  521. STRENTRY seReg[] =
  522. {
  523. // These two NT-specific entries must be at the end
  524. { "25", "%SystemRoot%" },
  525. { "11", "%SystemRoot%\\system32" },
  526. };
  527. STRTABLE stReg = { ARRAYSIZE(seReg), seReg };
  528. hr = pfnri(hInstance, pszSection, &stReg);
  529. }
  530. #else
  531. if (pfnri)
  532. {
  533. hr = pfnri(hInstance, pszSection, NULL);
  534. }
  535. #endif
  536. FreeLibrary(hinstAdvPack);
  537. }
  538. return hr;
  539. }