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.

550 lines
18 KiB

  1. #include <shlwapi.h>
  2. #include <regstr.h>
  3. #if (_WIN32_WINNT >= 0x0500)
  4. #include <lm.h> // for NetGetJoinInformation
  5. #endif
  6. // stolen from winuser
  7. #ifndef SM_REMOTESESSION
  8. #define SM_REMOTESESSION 0x1000
  9. #endif
  10. BOOL IsWinlogonRegValueSet(HKEY hKey, LPSTR pszKeyName, LPSTR pszPolicyKeyName, LPSTR pszValueName)
  11. {
  12. BOOL bRet = FALSE;
  13. DWORD dwType;
  14. DWORD dwSize;
  15. HKEY hkey;
  16. // first check the per-machine location.
  17. if (RegOpenKeyExA(hKey, pszKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
  18. {
  19. dwSize = sizeof(bRet);
  20. if (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)&bRet, &dwSize) == ERROR_SUCCESS)
  21. {
  22. if (dwType != REG_DWORD)
  23. {
  24. bRet = FALSE;
  25. }
  26. }
  27. RegCloseKey(hkey);
  28. }
  29. // then let the policy value override
  30. if (RegOpenKeyExA(hKey, pszPolicyKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
  31. {
  32. dwSize = sizeof(bRet);
  33. if (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)&bRet, &dwSize) == ERROR_SUCCESS)
  34. {
  35. if (dwType != REG_DWORD)
  36. {
  37. bRet = FALSE;
  38. }
  39. }
  40. RegCloseKey(hkey);
  41. }
  42. return bRet;
  43. }
  44. BOOL IsWinlogonRegValuePresent(HKEY hKey, LPSTR pszKeyName, LPSTR pszValueName)
  45. {
  46. BOOL bRet = FALSE;
  47. DWORD dwType;
  48. DWORD dwSize;
  49. HKEY hkey;
  50. // first check the per-machine location.
  51. if (RegOpenKeyExA(hKey, pszKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
  52. {
  53. char szValueData[MAX_PATH];
  54. dwSize = sizeof(szValueData);
  55. bRet = (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)szValueData, &dwSize) == ERROR_SUCCESS);
  56. RegCloseKey(hkey);
  57. }
  58. return bRet;
  59. }
  60. /*
  61. BOOL IsTermsrvRunning()
  62. {
  63. BOOL fResult = TRUE; // assume the service is running
  64. SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  65. if (hSCManager)
  66. {
  67. SC_HANDLE hSCService = OpenService(hSCManager, TEXT("TermService"), SERVICE_QUERY_CONFIG);
  68. if (hSCService)
  69. {
  70. SERVICE_STATUS ServiceStatus;
  71. if (QueryServiceStatus(hSCService, &ServiceStatus))
  72. {
  73. if ((ServiceStatus.dwCurrentState == SERVICE_START_PENDING) ||
  74. (ServiceStatus.dwCurrentState == SERVICE_RUNNING) ||
  75. (ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING))
  76. {
  77. fResult = FALSE;
  78. }
  79. }
  80. }
  81. CloseServiceHandle(hSCManager);
  82. }
  83. return fResult;
  84. }
  85. */
  86. #if (_WIN32_WINNT >= 0x0500)
  87. // Have to use a LoadLibrary/GetProcAddress thunk since we are part of stock4.lib/stock.lib,
  88. // and we can't require users of stocklib to delayload netapi32.dll
  89. typedef NET_API_STATUS (* NETGETJOININFORMATION) (LPCWSTR, LPWSTR*, PNETSETUP_JOIN_STATUS);
  90. NET_API_STATUS NT5_NetGetJoinInformation(LPCWSTR pszServer, LPWSTR* ppszNameBuffer, PNETSETUP_JOIN_STATUS BufferType)
  91. {
  92. static NETGETJOININFORMATION s_pfn = (NETGETJOININFORMATION)-1;
  93. if (s_pfn == (NETGETJOININFORMATION)-1)
  94. {
  95. if (IsOS(OS_WIN2000ORGREATER))
  96. {
  97. s_pfn = (NETGETJOININFORMATION)GetProcAddress(LoadLibrary(TEXT("netapi32")), "NetGetJoinInformation");
  98. }
  99. else
  100. {
  101. s_pfn = NULL;
  102. }
  103. }
  104. if (s_pfn)
  105. {
  106. return s_pfn(pszServer, ppszNameBuffer, BufferType);
  107. }
  108. else
  109. {
  110. return ERROR_PROC_NOT_FOUND;
  111. }
  112. }
  113. typedef NET_API_STATUS (* NETAPIBUFFERFREE) (void*);
  114. NET_API_STATUS NT5_NetApiBufferFree(LPVOID pv)
  115. {
  116. static NETAPIBUFFERFREE s_pfn = (NETAPIBUFFERFREE)-1;
  117. if (s_pfn == (NETAPIBUFFERFREE)-1)
  118. {
  119. if (IsOS(OS_WIN2000ORGREATER))
  120. {
  121. s_pfn = (NETAPIBUFFERFREE)GetProcAddress(GetModuleHandle(TEXT("netapi32")), "NetApiBufferFree");
  122. }
  123. else
  124. {
  125. s_pfn = NULL;
  126. }
  127. }
  128. if (s_pfn)
  129. {
  130. return s_pfn(pv);
  131. }
  132. else
  133. {
  134. return ERROR_PROC_NOT_FOUND;
  135. }
  136. }
  137. #endif // (_WIN32_WINNT >= 0x0500)
  138. // checks to see if this machine is a member of a domain or not
  139. // NOTE: this will always return FALSE on downlevel platforms (older than win2k)
  140. BOOL IsMachineDomainMember()
  141. {
  142. // don't call NetGetJoinInformation if we are part of stock4.lib
  143. #if (_WIN32_WINNT >= 0x0500)
  144. static BOOL s_bIsDomainMember = FALSE;
  145. static BOOL s_bDomainCached = FALSE;
  146. if (IsOS(OS_WIN2000ORGREATER) && !s_bDomainCached)
  147. {
  148. LPWSTR pwszDomain;
  149. NETSETUP_JOIN_STATUS njs;
  150. NET_API_STATUS nas;
  151. nas = NT5_NetGetJoinInformation(NULL, &pwszDomain, &njs);
  152. if (nas == NERR_Success)
  153. {
  154. if (pwszDomain)
  155. {
  156. NT5_NetApiBufferFree(pwszDomain);
  157. }
  158. if (njs == NetSetupDomainName)
  159. {
  160. // we are joined to a domain!
  161. s_bIsDomainMember = TRUE;
  162. }
  163. }
  164. s_bDomainCached = TRUE;
  165. }
  166. return s_bIsDomainMember;
  167. #else
  168. return FALSE;
  169. #endif
  170. }
  171. typedef LONG (WINAPI *PFNTQUERYINFORMATIONPROCESS) (HANDLE ProcessHandle, int ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
  172. // this function checks to see if we are a 32-bit process running on a 64-bit platform
  173. BOOL RunningOnWow64()
  174. {
  175. static BOOL bRunningOnWow64 = (BOOL)-1;
  176. if (bRunningOnWow64 == (BOOL)-1)
  177. {
  178. PFNTQUERYINFORMATIONPROCESS pfn = (PFNTQUERYINFORMATIONPROCESS)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtQueryInformationProcess");
  179. if (pfn)
  180. {
  181. LONG lStatus;
  182. ULONG_PTR Wow64Info;
  183. #define ProcessWow64Information 26 // stolen from ntpsapi.h
  184. lStatus = pfn(GetCurrentProcess(), ProcessWow64Information, &Wow64Info, sizeof(Wow64Info), NULL);
  185. if ((lStatus >= 0) && Wow64Info)
  186. {
  187. bRunningOnWow64 = TRUE;
  188. }
  189. else
  190. {
  191. bRunningOnWow64 = FALSE;
  192. }
  193. }
  194. else
  195. {
  196. bRunningOnWow64 = FALSE;
  197. }
  198. }
  199. return bRunningOnWow64;
  200. }
  201. BOOL ShouldShowServerAdminUI()
  202. {
  203. DWORD dw = FALSE;
  204. HKEY hk;
  205. if (RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER TEXT("\\Advanced"), 0, KEY_QUERY_VALUE, &hk) == ERROR_SUCCESS)
  206. {
  207. DWORD cb = sizeof(dw);
  208. RegQueryValueEx(hk, TEXT("ServerAdminUI"), NULL, NULL, (LPBYTE)&dw, &cb); // preinitialized dw for failure
  209. RegCloseKey(hk);
  210. }
  211. return dw;
  212. }
  213. BOOL IsApplianceServer()
  214. {
  215. static BOOL s_bRet = (BOOL)-1;
  216. // Cache the value since it should not change normally. If any of the
  217. // following code fails, just assume it is not an appliance server.
  218. if (s_bRet == (BOOL)-1)
  219. {
  220. HKEY hkey;
  221. if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "System\\WPA\\ApplianceServer", 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
  222. {
  223. DWORD dwType;
  224. DWORD dwValue;
  225. DWORD dwSize = sizeof(dwValue);
  226. if (RegQueryValueExA(hkey, "Installed", NULL, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS)
  227. {
  228. if ((dwType == REG_DWORD) && (dwValue != 0))
  229. {
  230. s_bRet = TRUE;
  231. }
  232. }
  233. RegCloseKey(hkey);
  234. }
  235. }
  236. if (s_bRet == (BOOL)-1)
  237. {
  238. s_bRet = FALSE;
  239. }
  240. return s_bRet;
  241. }
  242. /*----------------------------------------------------------
  243. Purpose: Returns TRUE/FALSE if the platform is the given OS_ value.
  244. */
  245. STDAPI_(BOOL) IsOS(DWORD dwOS)
  246. {
  247. BOOL bRet;
  248. static OSVERSIONINFOEXA s_osvi = {0};
  249. static BOOL s_bVersionCached = FALSE;
  250. if (!s_bVersionCached)
  251. {
  252. s_bVersionCached = TRUE;
  253. s_osvi.dwOSVersionInfoSize = sizeof(s_osvi);
  254. if (!GetVersionExA((OSVERSIONINFOA*)&s_osvi))
  255. {
  256. // If it failed, it must be a down level platform
  257. s_osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  258. GetVersionExA((OSVERSIONINFOA*)&s_osvi);
  259. }
  260. }
  261. switch (dwOS)
  262. {
  263. case OS_TERMINALCLIENT:
  264. // WARNING: this will only return TRUE for REMOTE TS sessions (eg you are comming in via tsclient).
  265. // If you want to see if TS is enabled or if the user is on the TS console, the use one of the other flags.
  266. bRet = GetSystemMetrics(SM_REMOTESESSION);
  267. break;
  268. case OS_WIN2000TERMINAL:
  269. // WARNING: this flag is VERY ambiguous... you probably want to use one of
  270. // OS_TERMINALSERVER, OS_TERMINALREMOTEADMIN, or OS_PERSONALTERMINALSERVER instead.
  271. RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use one of OS_TERMINALSERVER, OS_TERMINALREMOTEADMIN, or OS_PERSONALTERMINALSERVER instead !");
  272. bRet = ((VER_SUITE_TERMINAL & s_osvi.wSuiteMask) &&
  273. s_osvi.dwMajorVersion >= 5);
  274. break;
  275. case OS_TERMINALSERVER:
  276. // NOTE: be careful about using OS_TERMINALSERVER. It will only return true for nt server boxes
  277. // configured in what used to be called "Applications Server" mode in the win2k days. It is now simply called
  278. // "Terminal Server" (hence the name of this flag).
  279. bRet = ((VER_SUITE_TERMINAL & s_osvi.wSuiteMask) &&
  280. !(VER_SUITE_SINGLEUSERTS & s_osvi.wSuiteMask));
  281. #ifdef DEBUG
  282. if (bRet)
  283. {
  284. // all "Terminal Server" machines have to be server (cannot be per/pro)
  285. ASSERT(VER_NT_SERVER == s_osvi.wProductType || VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType);
  286. }
  287. #endif
  288. break;
  289. case OS_TERMINALREMOTEADMIN:
  290. // this checks to see if TS has been installed in the "Remote Administration" mode. This is
  291. // the default for server installs on win2k and whistler
  292. bRet = ((VER_SUITE_TERMINAL & s_osvi.wSuiteMask) &&
  293. (VER_SUITE_SINGLEUSERTS & s_osvi.wSuiteMask));
  294. break;
  295. case OS_PERSONALTERMINALSERVER:
  296. bRet = ((VER_SUITE_SINGLEUSERTS & s_osvi.wSuiteMask) &&
  297. !(VER_SUITE_TERMINAL & s_osvi.wSuiteMask));
  298. break;
  299. case OS_FASTUSERSWITCHING:
  300. bRet = (((VER_SUITE_TERMINAL | VER_SUITE_SINGLEUSERTS) & s_osvi.wSuiteMask) &&
  301. IsWinlogonRegValueSet(HKEY_LOCAL_MACHINE,
  302. "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
  303. "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\policies\\system",
  304. "AllowMultipleTSSessions"));
  305. break;
  306. case OS_FRIENDLYLOGONUI:
  307. bRet = ((VER_NT_WORKSTATION == s_osvi.wProductType) &&
  308. !IsMachineDomainMember() &&
  309. !IsWinlogonRegValuePresent(HKEY_LOCAL_MACHINE,
  310. "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
  311. "GinaDLL") &&
  312. IsWinlogonRegValueSet(HKEY_LOCAL_MACHINE,
  313. "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
  314. "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\policies\\system",
  315. "LogonType"));
  316. break;
  317. case OS_DOMAINMEMBER:
  318. bRet = IsMachineDomainMember();
  319. ASSERT(VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId); // has to be a NT machine to be on a domain!
  320. break;
  321. case 4: // used to be OS_NT5, is the same as OS_WIN2000ORGREATER so use that instead
  322. case OS_WIN2000ORGREATER:
  323. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
  324. s_osvi.dwMajorVersion >= 5);
  325. break;
  326. // NOTE: The flags in this section are bogus and SHOULD NOT BE USED
  327. // (but the ie4 shell32 uses them, so don't RIP on downlevel platforms)
  328. case OS_WIN2000PRO:
  329. RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use OS_PROFESSIONAL instead of OS_WIN2000PRO !");
  330. bRet = (VER_NT_WORKSTATION == s_osvi.wProductType &&
  331. s_osvi.dwMajorVersion == 5);
  332. break;
  333. case OS_WIN2000ADVSERVER:
  334. RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use OS_ADVSERVER instead of OS_WIN2000ADVSERVER !");
  335. bRet = ((VER_NT_SERVER == s_osvi.wProductType ||
  336. VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  337. s_osvi.dwMajorVersion == 5 &&
  338. (VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
  339. !(VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
  340. break;
  341. case OS_WIN2000DATACENTER:
  342. RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use OS_DATACENTER instead of OS_WIN2000DATACENTER !");
  343. bRet = ((VER_NT_SERVER == s_osvi.wProductType ||
  344. VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  345. s_osvi.dwMajorVersion == 5 &&
  346. (VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
  347. break;
  348. case OS_WIN2000SERVER:
  349. RIPMSG(!IsOS(OS_WHISTLERORGREATER), "IsOS: use OS_SERVER instead of OS_WIN2000SERVER !");
  350. bRet = ((VER_NT_SERVER == s_osvi.wProductType ||
  351. VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  352. !(VER_SUITE_DATACENTER & s_osvi.wSuiteMask) &&
  353. !(VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
  354. s_osvi.dwMajorVersion == 5);
  355. break;
  356. // END bogus Flags
  357. case OS_EMBEDDED:
  358. bRet = (VER_SUITE_EMBEDDEDNT & s_osvi.wSuiteMask);
  359. break;
  360. case OS_WINDOWS:
  361. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId);
  362. break;
  363. case OS_NT:
  364. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId);
  365. break;
  366. case OS_WIN95:
  367. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  368. s_osvi.dwMajorVersion >= 4);
  369. break;
  370. case OS_WIN95GOLD:
  371. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  372. s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion == 0 &&
  373. LOWORD(s_osvi.dwBuildNumber) == 950);
  374. break;
  375. case OS_WIN98ORGREATER:
  376. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  377. (s_osvi.dwMajorVersion > 4 ||
  378. s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion >= 10));
  379. break;
  380. case OS_WIN98_GOLD:
  381. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  382. s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion == 10 &&
  383. LOWORD(s_osvi.dwBuildNumber) == 1998);
  384. break;
  385. case OS_MILLENNIUMORGREATER:
  386. bRet = (VER_PLATFORM_WIN32_WINDOWS == s_osvi.dwPlatformId &&
  387. ((s_osvi.dwMajorVersion == 4 && s_osvi.dwMinorVersion >= 90) ||
  388. s_osvi.dwMajorVersion > 4));
  389. break;
  390. case OS_NT4:
  391. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
  392. s_osvi.dwMajorVersion >= 4);
  393. break;
  394. case OS_WHISTLERORGREATER:
  395. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
  396. ((s_osvi.dwMajorVersion > 5) ||
  397. (s_osvi.dwMajorVersion == 5 && (s_osvi.dwMinorVersion > 0 ||
  398. (s_osvi.dwMinorVersion == 0 && LOWORD(s_osvi.dwBuildNumber) > 2195)))));
  399. break;
  400. case OS_PERSONAL:
  401. bRet = (VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId &&
  402. (VER_SUITE_PERSONAL & s_osvi.wSuiteMask));
  403. break;
  404. case OS_PROFESSIONAL:
  405. bRet = ((VER_PLATFORM_WIN32_NT == s_osvi.dwPlatformId) &&
  406. (VER_NT_WORKSTATION == s_osvi.wProductType));
  407. break;
  408. case OS_DATACENTER:
  409. bRet = ((VER_NT_SERVER == s_osvi.wProductType || VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  410. (VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
  411. break;
  412. case OS_ADVSERVER:
  413. bRet = ((VER_NT_SERVER == s_osvi.wProductType || VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  414. (VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
  415. !(VER_SUITE_DATACENTER & s_osvi.wSuiteMask));
  416. break;
  417. case OS_SERVER:
  418. // NOTE: be careful! this specifically means Server -- will return false for Avanced Server and Datacenter machines
  419. bRet = ((VER_NT_SERVER == s_osvi.wProductType || VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType) &&
  420. !(VER_SUITE_DATACENTER & s_osvi.wSuiteMask) &&
  421. !(VER_SUITE_ENTERPRISE & s_osvi.wSuiteMask) &&
  422. !(VER_SUITE_BLADE & s_osvi.wSuiteMask) &&
  423. !(VER_SUITE_SMALLBUSINESS & s_osvi.wSuiteMask) &&
  424. !(VER_SUITE_SMALLBUSINESS_RESTRICTED & s_osvi.wSuiteMask));
  425. break;
  426. case OS_BLADE:
  427. // Blade has a direct suite mask
  428. bRet = (VER_SUITE_BLADE & s_osvi.wSuiteMask);
  429. break;
  430. case OS_SMALLBUSINESSSERVER:
  431. // SBS also has a direct suite mask
  432. bRet = (VER_SUITE_SMALLBUSINESS_RESTRICTED & s_osvi.wSuiteMask);
  433. break;
  434. case OS_ANYSERVER:
  435. // this is for people who want to know if this is ANY type of NT server machine (eg dtc, ads, or srv)
  436. bRet = ((VER_NT_SERVER == s_osvi.wProductType) || (VER_NT_DOMAIN_CONTROLLER == s_osvi.wProductType));
  437. break;
  438. case OS_WOW6432:
  439. bRet = RunningOnWow64();
  440. break;
  441. #if (_WIN32_WINNT >= 0x0501)
  442. case OS_TABLETPC:
  443. bRet = GetSystemMetrics(SM_TABLETPC);
  444. break;
  445. case OS_MEDIACENTER:
  446. bRet = GetSystemMetrics(SM_MEDIACENTER);
  447. break;
  448. case OS_APPLIANCE:
  449. bRet = IsApplianceServer();
  450. break;
  451. #endif
  452. case OS_SERVERADMINUI:
  453. // Note that it is possible to have server admin UI on a non-server machine.
  454. // This is to prevent "surprises" when an admin's profile roams to a non-server.
  455. // Otherwise the user gets a mix of admin settings (Start Menu, full path in
  456. // title bar, etc.) and nonadmin settings (hide taskbar icons, folder sniffing).
  457. //
  458. bRet = ShouldShowServerAdminUI();
  459. break;
  460. default:
  461. bRet = FALSE;
  462. break;
  463. }
  464. return bRet;
  465. }