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.

512 lines
12 KiB

  1. // util.cpp: Utility functions
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include <windows.h>
  5. #include <winbase.h> // for GetCommandLine
  6. #include "util.h"
  7. #include <debug.h>
  8. #include "resource.h"
  9. // I'm doing my own version of these functions because they weren't in win95.
  10. // These come from shell\shlwapi\strings.c.
  11. #ifdef UNIX
  12. #ifdef BIG_ENDIAN
  13. #define READNATIVEWORD(x) MAKEWORD(*(char*)(x), *(char*)((char*)(x) + 1))
  14. #else
  15. #define READNATIVEWORD(x) MAKEWORD(*(char*)((char*)(x) + 1), *(char*)(x))
  16. #endif
  17. #else
  18. #define READNATIVEWORD(x) (*(UNALIGNED WORD *)x)
  19. #endif
  20. /*
  21. * ChrCmp - Case sensitive character comparison for DBCS
  22. * Assumes w1, wMatch are characters to be compared
  23. * Return FALSE if they match, TRUE if no match
  24. */
  25. __inline BOOL ChrCmpA_inline(WORD w1, WORD wMatch)
  26. {
  27. /* Most of the time this won't match, so test it first for speed.
  28. */
  29. if (LOBYTE(w1) == LOBYTE(wMatch))
  30. {
  31. if (IsDBCSLeadByte(LOBYTE(w1)))
  32. {
  33. return(w1 != wMatch);
  34. }
  35. return FALSE;
  36. }
  37. return TRUE;
  38. }
  39. /*
  40. * StrRChr - Find last occurrence of character in string
  41. * Assumes lpStart points to start of string
  42. * lpEnd points to end of string (NOT included in search)
  43. * wMatch is the character to match
  44. * returns ptr to the last occurrence of ch in str, NULL if not found.
  45. */
  46. LPSTR StrRChr(LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch)
  47. {
  48. LPCSTR lpFound = NULL;
  49. ASSERT(lpStart);
  50. ASSERT(!lpEnd || lpEnd <= lpStart + lstrlenA(lpStart));
  51. if (!lpEnd)
  52. lpEnd = lpStart + lstrlenA(lpStart);
  53. for ( ; lpStart < lpEnd; lpStart = AnsiNext(lpStart))
  54. {
  55. // (ChrCmp returns FALSE when characters match)
  56. if (!ChrCmpA_inline(READNATIVEWORD(lpStart), wMatch))
  57. lpFound = lpStart;
  58. }
  59. return ((LPSTR)lpFound);
  60. }
  61. /*
  62. * StrChr - Find first occurrence of character in string
  63. * Assumes lpStart points to start of null terminated string
  64. * wMatch is the character to match
  65. * returns ptr to the first occurrence of ch in str, NULL if not found.
  66. */
  67. LPSTR _StrChrA(LPCSTR lpStart, WORD wMatch, BOOL fMBCS)
  68. {
  69. if (fMBCS) {
  70. for ( ; *lpStart; lpStart = AnsiNext(lpStart))
  71. {
  72. if (!ChrCmpA_inline(READNATIVEWORD(lpStart), wMatch))
  73. return((LPSTR)lpStart);
  74. }
  75. } else {
  76. for ( ; *lpStart; lpStart++)
  77. {
  78. if ((BYTE)*lpStart == LOBYTE(wMatch)) {
  79. return((LPSTR)lpStart);
  80. }
  81. }
  82. }
  83. return (NULL);
  84. }
  85. LPSTR StrChr(LPCSTR lpStart, WORD wMatch)
  86. {
  87. CPINFO cpinfo;
  88. return _StrChrA(lpStart, wMatch, GetCPInfo(CP_ACP, &cpinfo) && cpinfo.LeadByte[0]);
  89. }
  90. // LoadStringExW and LoadStringAuto are stolen from shell\ext\mlang\util.cpp
  91. //
  92. // Extend LoadString() to to _LoadStringExW() to take LangId parameter
  93. int LoadStringExW(
  94. HMODULE hModule,
  95. UINT wID,
  96. LPWSTR lpBuffer, // Unicode buffer
  97. int cchBufferMax, // cch in Unicode buffer
  98. WORD wLangId)
  99. {
  100. HRSRC hResInfo;
  101. HANDLE hStringSeg;
  102. LPWSTR lpsz;
  103. int cch;
  104. // Make sure the parms are valid.
  105. if (lpBuffer == NULL || cchBufferMax == 0)
  106. {
  107. return 0;
  108. }
  109. cch = 0;
  110. // String Tables are broken up into 16 string segments. Find the segment
  111. // containing the string we are interested in.
  112. if (hResInfo = FindResourceExW(hModule, (LPCWSTR)RT_STRING,
  113. (LPWSTR)IntToPtr(((USHORT)wID >> 4) + 1), wLangId))
  114. {
  115. // Load that segment.
  116. hStringSeg = LoadResource(hModule, hResInfo);
  117. // Lock the resource.
  118. if (lpsz = (LPWSTR)LockResource(hStringSeg))
  119. {
  120. // Move past the other strings in this segment.
  121. // (16 strings in a segment -> & 0x0F)
  122. wID &= 0x0F;
  123. while (TRUE)
  124. {
  125. cch = *((WORD *)lpsz++); // PASCAL like string count
  126. // first UTCHAR is count if TCHARs
  127. if (wID-- == 0) break;
  128. lpsz += cch; // Step to start if next string
  129. }
  130. // Account for the NULL
  131. cchBufferMax--;
  132. // Don't copy more than the max allowed.
  133. if (cch > cchBufferMax)
  134. cch = cchBufferMax-1;
  135. // Copy the string into the buffer.
  136. CopyMemory(lpBuffer, lpsz, cch*sizeof(WCHAR));
  137. // Attach Null terminator.
  138. lpBuffer[cch] = 0;
  139. }
  140. }
  141. return cch;
  142. }
  143. #define LCID_ENGLISH 0x409
  144. // LoadString from the correct resource
  145. // try to load in the system default language
  146. // fall back to english if fail
  147. int LoadStringAuto(
  148. HMODULE hModule,
  149. UINT wID,
  150. LPSTR lpBuffer,
  151. int cchBufferMax)
  152. {
  153. int iRet = 0;
  154. LPWSTR lpwStr = (LPWSTR) LocalAlloc(LPTR, cchBufferMax*sizeof(WCHAR));
  155. if (lpwStr)
  156. {
  157. iRet = LoadStringExW(hModule, wID, lpwStr, cchBufferMax, GetSystemDefaultLangID());
  158. if (!iRet)
  159. {
  160. iRet = LoadStringExW(hModule, wID, lpwStr, cchBufferMax, LCID_ENGLISH);
  161. }
  162. if (iRet)
  163. iRet = WideCharToMultiByte(CP_ACP, 0, lpwStr, iRet, lpBuffer, cchBufferMax, NULL, NULL);
  164. if(iRet >= cchBufferMax)
  165. iRet = cchBufferMax-1;
  166. lpBuffer[iRet] = 0;
  167. LocalFree(lpwStr);
  168. }
  169. return iRet;
  170. }
  171. #define WS_EX_LAYOUTRTL 0x00400000L // Right to left mirroring
  172. BOOL Mirror_IsWindowMirroredRTL(HWND hWnd)
  173. {
  174. return (GetWindowLongA( hWnd , GWL_EXSTYLE ) & WS_EX_LAYOUTRTL );
  175. }
  176. BOOL _PathRemoveFileSpec(LPTSTR psz)
  177. {
  178. TCHAR * pszT = StrRChr( psz, psz+lstrlen(psz)-1, TEXT('\\') );
  179. if (pszT)
  180. {
  181. *(pszT+1) = NULL;
  182. return TRUE;
  183. }
  184. else
  185. {
  186. return FALSE;
  187. }
  188. }
  189. void PathAppend(LPTSTR pszPath, LPTSTR pMore)
  190. {
  191. lstrcpy(pszPath+lstrlen(pszPath), pMore);
  192. }
  193. BOOL PathFileExists(LPTSTR pszPath)
  194. {
  195. BOOL fResult = FALSE;
  196. DWORD dwErrMode;
  197. dwErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  198. fResult = ((UINT)GetFileAttributes(pszPath) != (UINT)-1);
  199. SetErrorMode(dwErrMode);
  200. return fResult;
  201. }
  202. BOOL _IsNT()
  203. {
  204. BOOL fRet = FALSE;
  205. OSVERSIONINFO osv;
  206. osv.dwOSVersionInfoSize = sizeof(osv);
  207. if (GetVersionEx(&osv) &&
  208. VER_PLATFORM_WIN32_NT == osv.dwPlatformId)
  209. {
  210. fRet = TRUE;
  211. }
  212. return fRet;
  213. }
  214. BOOL _IsNTServer()
  215. {
  216. BOOL fRet = FALSE;
  217. HKEY hKey;
  218. if (ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"), 0, KEY_QUERY_VALUE, &hKey ))
  219. {
  220. TCHAR szProductType[80];
  221. DWORD dwBufLen = sizeof(szProductType);
  222. if (ERROR_SUCCESS == RegQueryValueEx( hKey, "ProductType", NULL, NULL, (LPBYTE) szProductType, &dwBufLen))
  223. {
  224. if (!lstrcmpi("SERVERNT", szProductType) ||
  225. !lstrcmpi("LANMANNT", szProductType))
  226. {
  227. fRet = TRUE;
  228. }
  229. }
  230. RegCloseKey(hKey);
  231. }
  232. return fRet;
  233. }
  234. BOOL IsCheckableOS()
  235. {
  236. BOOL fCheckable = FALSE;
  237. OSVERSIONINFO osv;
  238. osv.dwOSVersionInfoSize = sizeof(osv);
  239. if (GetVersionEx(&osv))
  240. {
  241. if (VER_PLATFORM_WIN32_WINDOWS == osv.dwPlatformId) // Win9X
  242. {
  243. if (osv.dwMinorVersion > 0) // not Win95
  244. {
  245. fCheckable = TRUE;
  246. }
  247. }
  248. else if (VER_PLATFORM_WIN32_NT == osv.dwPlatformId) // WinNT
  249. {
  250. if ((osv.dwMajorVersion >= 4) &&
  251. !_IsNTServer()) // only support NT4 and higher, no server SKUs
  252. {
  253. fCheckable = TRUE;
  254. }
  255. }
  256. }
  257. return fCheckable;
  258. }
  259. BOOL
  260. _IsUserAdmin(
  261. VOID
  262. )
  263. /*++
  264. Routine Description:
  265. This routine returns TRUE if the caller's process is a
  266. member of the Administrators local group.
  267. Caller is NOT expected to be impersonating anyone and IS
  268. expected to be able to open their own process and process
  269. token.
  270. Arguments:
  271. None.
  272. Return Value:
  273. TRUE - Caller has Administrators local group.
  274. FALSE - Caller does not have Administrators local group.
  275. --*/
  276. {
  277. HANDLE Token;
  278. DWORD BytesRequired;
  279. PTOKEN_GROUPS Groups;
  280. BOOL b;
  281. DWORD i;
  282. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  283. PSID AdministratorsGroup;
  284. //
  285. // On non-NT platforms the user is administrator.
  286. //
  287. if(!_IsNT()) {
  288. return(TRUE);
  289. }
  290. //
  291. // Open the process token.
  292. //
  293. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
  294. return(FALSE);
  295. }
  296. b = FALSE;
  297. Groups = NULL;
  298. //
  299. // Get group information.
  300. //
  301. if(!GetTokenInformation(Token,TokenGroups,NULL,0,&BytesRequired)
  302. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  303. && (Groups = (PTOKEN_GROUPS)LocalAlloc(LPTR,BytesRequired))
  304. && GetTokenInformation(Token,TokenGroups,Groups,BytesRequired,&BytesRequired)) {
  305. b = AllocateAndInitializeSid(
  306. &NtAuthority,
  307. 2,
  308. SECURITY_BUILTIN_DOMAIN_RID,
  309. DOMAIN_ALIAS_RID_ADMINS,
  310. 0, 0, 0, 0, 0, 0,
  311. &AdministratorsGroup
  312. );
  313. if(b) {
  314. //
  315. // See if the user has the administrator group.
  316. //
  317. b = FALSE;
  318. for(i=0; i<Groups->GroupCount; i++) {
  319. if(EqualSid(Groups->Groups[i].Sid,AdministratorsGroup)) {
  320. b = TRUE;
  321. break;
  322. }
  323. }
  324. FreeSid(AdministratorsGroup);
  325. }
  326. }
  327. //
  328. // Clean up and return.
  329. //
  330. if(Groups) {
  331. LocalFree((HLOCAL)Groups);
  332. }
  333. CloseHandle(Token);
  334. return(b);
  335. }
  336. BOOL
  337. _DoesUserHavePrivilege(
  338. PTSTR PrivilegeName
  339. )
  340. /*++
  341. Routine Description:
  342. This routine returns TRUE if the caller's process has
  343. the specified privilege. The privilege does not have
  344. to be currently enabled. This routine is used to indicate
  345. whether the caller has the potential to enable the privilege.
  346. Caller is NOT expected to be impersonating anyone and IS
  347. expected to be able to open their own process and process
  348. token.
  349. Arguments:
  350. Privilege - the name form of privilege ID (such as
  351. SE_SECURITY_NAME).
  352. Return Value:
  353. TRUE - Caller has the specified privilege.
  354. FALSE - Caller does not have the specified privilege.
  355. --*/
  356. {
  357. HANDLE Token;
  358. ULONG BytesRequired;
  359. PTOKEN_PRIVILEGES Privileges;
  360. BOOL b;
  361. DWORD i;
  362. LUID Luid;
  363. //
  364. // On non-NT platforms the user has all privileges
  365. //
  366. if(!_IsNT()) {
  367. return(TRUE);
  368. }
  369. //
  370. // Open the process token.
  371. //
  372. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&Token)) {
  373. return(FALSE);
  374. }
  375. b = FALSE;
  376. Privileges = NULL;
  377. //
  378. // Get privilege information.
  379. //
  380. if(!GetTokenInformation(Token,TokenPrivileges,NULL,0,&BytesRequired)
  381. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  382. && (Privileges = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR,BytesRequired))
  383. && GetTokenInformation(Token,TokenPrivileges,Privileges,BytesRequired,&BytesRequired)
  384. && LookupPrivilegeValue(NULL,PrivilegeName,&Luid)) {
  385. //
  386. // See if we have the requested privilege
  387. //
  388. for(i=0; i<Privileges->PrivilegeCount; i++) {
  389. if(!memcmp(&Luid,&Privileges->Privileges[i].Luid,sizeof(LUID))) {
  390. b = TRUE;
  391. break;
  392. }
  393. }
  394. }
  395. //
  396. // Clean up and return.
  397. //
  398. if(Privileges) {
  399. LocalFree((HLOCAL)Privileges);
  400. }
  401. CloseHandle(Token);
  402. return(b);
  403. }
  404. BOOL IsUserRestricted()
  405. {
  406. return (!_IsUserAdmin() ||
  407. !_DoesUserHavePrivilege(SE_SHUTDOWN_NAME) ||
  408. !_DoesUserHavePrivilege(SE_BACKUP_NAME) ||
  409. !_DoesUserHavePrivilege(SE_RESTORE_NAME) ||
  410. !_DoesUserHavePrivilege(SE_SYSTEM_ENVIRONMENT_NAME));
  411. }