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.

536 lines
16 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. // Define registry section and value
  6. #define DSA_CONFIG_SECTION TEXT("System\\CurrentControlSet\\Services\\NTDS\\Parameters")
  7. #define SCHEMAVERSION TEXT("Schema Version")
  8. BOOL
  9. IsNT5DC()
  10. /*++
  11. Routine Descrtiption:
  12. Checks if a machine is a NT5 DC. Uses a call to RtlGetProductType that
  13. requires ntdll.dll. Since ntdll.dll is not loaded for x86 versions of
  14. setup (since they have to run on Windows95 too), loads ntdll.dll
  15. dynamically (for alphas, ntdll.dll.is already loaded and LoadLibrary
  16. returns a handle to it). So this function should be called only after
  17. checking that the current system is NT
  18. Currently, this function is called only for NT5 upgrades
  19. Arguments:
  20. None
  21. Return Value:
  22. TRUE if the machine is a NT5 DC, FALSE otherwise
  23. --*/
  24. {
  25. NT_PRODUCT_TYPE Type = NtProductWinNt;
  26. HMODULE h;
  27. TCHAR DllName[MAX_PATH];
  28. VOID (*GetPrType)(NT_PRODUCT_TYPE *Typ);
  29. if (OsVersion.dwMajorVersion != 5) {
  30. // not NT5
  31. return FALSE;
  32. }
  33. // Load ntdll.dll from the system directory
  34. // NTRAID#NTBUG9-585620-2002/03/25-lucios. Pending Fix.
  35. GetSystemDirectory(DllName, MAX_PATH);
  36. // NTRAID#NTBUG9-585639-2002/03/25-lucios. Pending Fix.
  37. ConcatenatePaths(DllName, TEXT("ntdll.dll"), MAX_PATH);
  38. //NOTICE-2002/03/25-lucios. LoadLibrary is using the complete path.
  39. if (h = LoadLibrary(DllName)) {
  40. // NOTICE-2002/03/25-lucios. RtlGetNtProductType is void, which makes
  41. // the reader wonder if it can fail. Since Type is initialized
  42. // there seems to be no risk.
  43. if((FARPROC) GetPrType = GetProcAddress(h, "RtlGetNtProductType")) {
  44. GetPrType(&Type);
  45. }
  46. FreeLibrary(h);
  47. }
  48. if ( Type == NtProductLanManNt ) {
  49. return TRUE;
  50. }
  51. else {
  52. return FALSE;
  53. }
  54. }
  55. BOOL
  56. ISDC()
  57. /*++
  58. Routine Descrtiption:
  59. Checks if a machine is a DC. Uses a call to RtlGetProductType that
  60. requires ntdll.dll. Since ntdll.dll is not loaded for x86 versions of
  61. setup (since they have to run on Windows95 too), loads ntdll.dll
  62. dynamically (for alphas, ntdll.dll.is already loaded and LoadLibrary
  63. returns a handle to it).
  64. Arguments:
  65. None
  66. Return Value:
  67. TRUE if the machine is a DC, FALSE otherwise
  68. --*/
  69. {
  70. NT_PRODUCT_TYPE Type = NtProductWinNt;
  71. HMODULE h;
  72. TCHAR DllName[MAX_PATH];
  73. VOID (*GetPrType)(NT_PRODUCT_TYPE *Typ);
  74. if (!ISNT()) {
  75. // not NT
  76. return FALSE;
  77. }
  78. // Load ntdll.dll from the system directory
  79. // NTRAID#NTBUG9-585620-2002/03/25-lucios. Pending Fix.
  80. GetSystemDirectory(DllName, MAX_PATH);
  81. // NTRAID#NTBUG9-585639-2002/03/25-lucios. Pending Fix.
  82. ConcatenatePaths(DllName, TEXT("ntdll.dll"), MAX_PATH);
  83. //NOTICE-2002/03/25-lucios. LoadLibrary is using the complete path and
  84. // Type is initialized.
  85. if (h = LoadLibrary(DllName)) {
  86. if((FARPROC) GetPrType = GetProcAddress(h, "RtlGetNtProductType")) {
  87. GetPrType(&Type);
  88. }
  89. FreeLibrary(h);
  90. }
  91. if ( Type == NtProductLanManNt ) {
  92. return TRUE;
  93. }
  94. else {
  95. return FALSE;
  96. }
  97. }
  98. int
  99. GetObjVersionInIniFile(
  100. IN TCHAR *IniFileName,
  101. OUT DWORD *Version
  102. )
  103. /*++
  104. Routine Decsription:
  105. Reads the Object-Version key in the SCHEMA section of the
  106. given ini file and returns the value in *Version. If the
  107. key cannot be read, 0 is returned in *Version
  108. Arguments:
  109. IniFileName - Pointer to null-terminated inifile name
  110. Version - Pointer to DWORD to return version in
  111. Return Value:
  112. 0
  113. --*/
  114. {
  115. // NTRAID#NTBUG9-585691-2002/03/25-lucios. Pending Fix on the two args.
  116. TCHAR Buffer[32];
  117. BOOL fFound = FALSE;
  118. LPCTSTR SCHEMASECTION = TEXT("SCHEMA");
  119. LPCTSTR OBJECTVER = TEXT("objectVersion");
  120. LPCTSTR DEFAULT = TEXT("NOT_FOUND");
  121. *Version = 0;
  122. // NTRAID#NTBUG9-585681-2002/03/25-lucios. Pending Fix.
  123. GetPrivateProfileString(
  124. SCHEMASECTION,
  125. OBJECTVER,
  126. DEFAULT,
  127. Buffer,
  128. sizeof(Buffer)/sizeof(TCHAR),
  129. IniFileName
  130. );
  131. //NOTICE-2002/03/25-lucios. This use of lstrcmpi seems safe, since
  132. // buffer is locally allocated and DEFAULT limits the char enummeration.
  133. // If DEFAULT grows in the future this might be a problem.
  134. if ( lstrcmpi(Buffer, DEFAULT) ) {
  135. // Not the default string, so got a value
  136. *Version = _ttoi(Buffer);
  137. fFound = TRUE;
  138. }
  139. return 0;
  140. }
  141. BOOL
  142. NtdsCheckSchemaVersion(
  143. IN TCHAR *IniFileName,
  144. OUT DWORD *DCVersion,
  145. OUT DWORD *IniVersion
  146. )
  147. /*++
  148. Routine Description:
  149. Reads a particular registry key, a key value from a given inifile
  150. and compares them.
  151. Arguments:
  152. IniFileName - Pointer to null-terminated inifile name to read key from
  153. DCVersion - Pointer to DWORD to return the registry key value in DC
  154. IniVersion - Pointer to DWORD to return the key value read from inifile
  155. Return:
  156. TRUE if the two values match, FALSE otherwise
  157. --*/
  158. {
  159. // NTRAID#NTBUG9-585691-2002/03/25-lucios. Pending Fix on the three args.
  160. // NTRAID#NTBUG9-585727-2002/03/25-lucios. Pending Fix.
  161. DWORD regVersion = 0, objVersion = 0;
  162. DWORD herr, err, dwType, dwSize;
  163. HKEY hk;
  164. // Read the "Schema Version" value from NTDS config section in registry
  165. // Value is assumed to be 0 if not found
  166. dwSize = sizeof(regVersion);
  167. //NOTICE-2002/03/25-lucios. RegOpenKey is being used
  168. // istead of RegOpenKeyEx, this means that we are opening with
  169. // full access. err is not being used.
  170. if ( (herr = RegOpenKey(HKEY_LOCAL_MACHINE, DSA_CONFIG_SECTION, &hk)) ||
  171. (err = RegQueryValueEx(hk, SCHEMAVERSION, NULL, &dwType, (LPBYTE) &regVersion, &dwSize)) ) {
  172. // Error getting the key. We assume it is not there
  173. regVersion = 0;
  174. }
  175. if (!herr) RegCloseKey(hk);
  176. // Get key value in inifile
  177. //NOTICE-2002/03/25-lucios. GetObjVersionInIniFile doesn't return an error
  178. GetObjVersionInIniFile( IniFileName, &objVersion );
  179. // Return the two values, and compare and return appropriate boolean
  180. *DCVersion = regVersion;
  181. *IniVersion = objVersion;
  182. if (regVersion != objVersion) {
  183. return FALSE;
  184. }
  185. return TRUE;
  186. }
  187. int
  188. MyCopyFileEx(
  189. IN HWND ParentWnd,
  190. IN TCHAR *TargetPath,
  191. IN TCHAR *FileName
  192. )
  193. /*++
  194. Routine Description:
  195. Copies the file specified by filename from the first source
  196. (NativeSourcePaths[0]) to TargetPath.
  197. Arguments:
  198. ParentWnd - Handle to parent window to raise appropriate error popups
  199. FileName - Pointer to null-terminated string containg name of file to copy
  200. Return Value:
  201. DSCHECK_ERR_FILE_NOT_FOUND if file is not found on source
  202. DSCHECK_ERR_FILE_COPY if error copying file
  203. DSCHECK_ERR_SUCCESS otherwise
  204. Also raises appropriate error popups too inform users
  205. --*/
  206. {
  207. // NTRAID#NTBUG9-585691-2002/03/25-lucios. Pending Fix on the two args, or
  208. // maybe even on ParentWnd for NULL and/or IsWindow(ParentWnd)
  209. TCHAR SourceName[MAX_PATH], ActualSourceName[MAX_PATH];
  210. TCHAR TargetName[MAX_PATH];
  211. HANDLE FindHandle;
  212. WIN32_FIND_DATA FindData;
  213. int err = 0;
  214. // Create the source file name
  215. // NTRAID#NTBUG9-585706-2002/03/25-lucios.
  216. lstrcpy(SourceName, NativeSourcePaths[0]);
  217. // First check if the uncompressed file is there
  218. // NTRAID#NTBUG9-585639-2002/03/25-lucios. Pending Fix.
  219. ConcatenatePaths(SourceName, FileName, MAX_PATH);
  220. FindHandle = FindFirstFile(SourceName, &FindData);
  221. if (FindHandle && (FindHandle != INVALID_HANDLE_VALUE)) {
  222. //
  223. // Got the file, copy name in ActualSourceName
  224. //
  225. FindClose(FindHandle);
  226. // NTRAID#NTBUG9-585706-2002/03/25-lucios.
  227. lstrcpy( ActualSourceName, SourceName );
  228. } else {
  229. //
  230. // Don't have the file, try the compressed file name
  231. //
  232. GenerateCompressedName(SourceName,ActualSourceName);
  233. FindHandle = FindFirstFile(ActualSourceName, &FindData);
  234. if (FindHandle && (FindHandle != INVALID_HANDLE_VALUE)) {
  235. // Got the file. Name is already in ActualSourceName
  236. FindClose(FindHandle);
  237. } else {
  238. ActualSourceName[0] = 0;
  239. }
  240. }
  241. if ( !ActualSourceName[0] ) {
  242. // file is not found. Error
  243. MessageBoxFromMessage(
  244. ParentWnd,
  245. MSG_DSCHECK_REQD_FILE_MISSING,
  246. FALSE,
  247. AppTitleStringId,
  248. MB_OK | MB_ICONWARNING | MB_TASKMODAL,
  249. FileName,
  250. NativeSourcePaths[0]
  251. );
  252. return DSCHECK_ERR_FILE_NOT_FOUND;
  253. }
  254. // Ok, the source file is there. Create target file name
  255. // NTRAID#NTBUG9-585706-2002/03/25-lucios.
  256. lstrcpy(TargetName, TargetPath);
  257. // NTRAID#NTBUG9-585639-2002/03/25-lucios. Pending Fix.
  258. ConcatenatePaths(TargetName, FileName, MAX_PATH);
  259. // Delete any existing file of the same name
  260. DeleteFile(TargetName);
  261. err = SetupapiDecompressOrCopyFile (ActualSourceName, TargetName, 0);
  262. if (err) {
  263. // some error copying file. Raise message box
  264. MessageBoxFromMessage(
  265. ParentWnd,
  266. MSG_DSCHECK_COPY_ERROR,
  267. FALSE,
  268. AppTitleStringId,
  269. MB_OK | MB_ICONWARNING | MB_TASKMODAL,
  270. FileName,
  271. NativeSourcePaths[0]
  272. );
  273. return DSCHECK_ERR_FILE_COPY;
  274. }
  275. // successfully copied file
  276. return DSCHECK_ERR_SUCCESS;
  277. }
  278. int
  279. MyCopyFile(
  280. IN HWND ParentWnd,
  281. IN TCHAR *FileName
  282. )
  283. /*++
  284. Routine Description:
  285. Copies the file specified by filename from the first source
  286. (NativeSourcePaths[0]). Files are copied to the system directory, except
  287. schema.ini, which is copied into windows directory since we do not
  288. want to overwrite the current schema.ini in the system directory of
  289. the DC
  290. Arguments:
  291. ParentWnd - Handle to parent window to raise appropriate error popups
  292. FileName - Pointer to null-terminated string containg name of file to copy
  293. Return Value:
  294. DSCHECK_ERR_FILE_NOT_FOUND if file is not found on source
  295. DSCHECK_ERR_FILE_COPY if error copying file
  296. DSCHECK_ERR_SUCCESS otherwise
  297. Also raises appropriate error popups too inform users
  298. --*/
  299. {
  300. // NTRAID#NTBUG9-585691-2002/03/25-lucios. Pending Fix on the first arg, or
  301. // maybe even on ParentWnd for NULL and/or IsWindow(ParentWnd)
  302. TCHAR TargetPath[MAX_PATH];
  303. int err = 0;
  304. //
  305. // Create target path, for schema.ini, copy it to windows directory
  306. //
  307. // NTRAID#NTBUG9-585620-2002/03/25-lucios. Pending Fix.
  308. // MyGetWindowsDirectory also returns a value that should be checked
  309. if (lstrcmpi(FileName, TEXT("schema.ini")) == 0) {
  310. MyGetWindowsDirectory(TargetPath, MAX_PATH) ;
  311. }
  312. else {
  313. GetSystemDirectory(TargetPath, MAX_PATH);
  314. }
  315. err = MyCopyFileEx(ParentWnd, TargetPath, FileName);
  316. return( err );
  317. }
  318. int
  319. CheckSchemaVersionForNT5DCs(
  320. IN HWND ParentWnd
  321. )
  322. /*++
  323. Routine Description:
  324. Main routine called from Options wizard page to initiate schema version
  325. check
  326. Arguments:
  327. ParentWnd - Handle to parent window to raise errors
  328. Return Value:
  329. DSCHECK_ERR_FILE_NOT_FOUND if a required file is not found
  330. DSCHECK_ERR_FILE_COPY if error copying a required file
  331. DSCHECK_ERR_SCHEMA_MISMATCH if schema versions do not match
  332. DSCHECK_ERR_SUCCESS otherwise
  333. Also pops up appropriate error windows on DSCHECK_ERR_SCHEMA_MISMATCH.
  334. Error Windows for the other errors are opened by downlevel routines
  335. --*/
  336. {
  337. // NTRAID#NTBUG9-585691-2002/03/25-lucios. Maybe the argument
  338. // should be checked for NULL and/or IsWindow(ParentWnd)
  339. TCHAR FileName[MAX_PATH];
  340. TCHAR IniFilePath[MAX_PATH];
  341. TCHAR IniVerStr[32], RegVerStr[32], TempStr[32];
  342. DWORD RegVer, IniVer, i;
  343. int err;
  344. int err1=0;
  345. if (!IsNT5DC()) {
  346. // Not an NT5 DC, nothing to do
  347. return DSCHECK_ERR_SUCCESS;
  348. }
  349. // copy the schema.ini to the local windows directory
  350. // NTRAID#NTBUG9-585706-2002/03/25-lucios.
  351. // FileName has a maximum that should be used, though it
  352. // is unlikelly that this can cause any problem
  353. lstrcpy(FileName, TEXT("schema.ini"));
  354. err = MyCopyFile(ParentWnd, FileName);
  355. if (err) {
  356. // return DSCHECK error returned by MyCopyFile
  357. return err;
  358. }
  359. // The schema.ini is now copied to windows directory.
  360. // Do schema version check
  361. // NTRAID#NTBUG9-585620-2002/03/25-lucios. Pending Fix.
  362. MyGetWindowsDirectory(IniFilePath, MAX_PATH);
  363. // NTRAID#NTBUG9-585639-2002/03/25-lucios. Pending Fix.
  364. ConcatenatePaths(IniFilePath, TEXT("schema.ini"), MAX_PATH);
  365. if ( NtdsCheckSchemaVersion( IniFilePath, &RegVer, &IniVer) ) {
  366. // The schema versions match. Nothing to do
  367. return DSCHECK_ERR_SUCCESS;
  368. }
  369. // We are here means schema versions do not match.
  370. // Copy all necesary files for schema upgrades.
  371. //NOTICE-2002/03/25-lucios. IniVerStr and RegVerStr are large enough.
  372. _itot(IniVer, IniVerStr, 10);
  373. _itot(RegVer, RegVerStr, 10);
  374. if ( (RegVer < 10) && (IniVer >= 10) ) {
  375. // Trying to upgrade from before B3-RC1 to B3-RC1 or above.
  376. // B3-RC1 or above requires a clean install due to incompatible
  377. // DS checkins. No upgrades are possible. Pop up the clean install
  378. // message and leave
  379. MessageBoxFromMessage(
  380. ParentWnd,
  381. MSG_DSCHECK_SCHEMA_CLEAN_INSTALL_NEEDED,
  382. FALSE,
  383. AppTitleStringId,
  384. MB_OK | MB_ICONERROR | MB_TASKMODAL,
  385. RegVerStr,
  386. IniVerStr
  387. );
  388. return DSCHECK_ERR_VERSION_MISMATCH;
  389. }
  390. if (RegVer == 16) {
  391. // trying to upgrade a machine in an enterprise with schema
  392. // version of 16 (Whistler-Beta1)
  393. // possibly, there are beta1 machines lying around
  394. // so we have to tell them to demote them before they continue
  395. i = MessageBoxFromMessage(
  396. ParentWnd,
  397. MSG_DSCHECK_SCHEMA_WHISTLER_BETA1_DETECTED,
  398. FALSE,
  399. AppTitleStringId,
  400. MB_OKCANCEL | MB_ICONWARNING | MB_TASKMODAL,
  401. NULL
  402. );
  403. if(i == IDCANCEL) {
  404. return DSCHECK_ERR_VERSION_MISMATCH;
  405. }
  406. }
  407. if ( RegVer > IniVer ) {
  408. // The schema version in the enterprise is already greater than
  409. // the schema version of the build you are trying to upgrade to.
  410. //
  411. // This is okay. Imagine upgrading a 5.0 DC to the next service
  412. // pack even though the 5.0 DC is in a domain of mixed 5.0 and
  413. // 5.1 DCs. The schema version for the 5.0 DC is the same as the
  414. // schema version for the 5.1 DCs because schema upgrades replicate
  415. // to all DCs in an enterprise. There is no reason to disallow
  416. // upgrading the 5.0 DC to the next service pack even though
  417. // the schema version of the service pack (IniVer) is less than
  418. // the schema version of the 5.0 DC (RegVer).
  419. return DSCHECK_ERR_SUCCESS;
  420. }
  421. return DSCHECK_ERR_SUCCESS;
  422. }