- NDK fix: don't undef a million status codes, instead, have apps define WIN32_NO_STATUS.
[reactos.git] / reactos / lib / syssetup / install.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS system libraries
23 * PURPOSE: System setup
24 * FILE: lib/syssetup/install.c
25 * PROGRAMER: Eric Kohl
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #define WIN32_NO_STATUS
31 #include <windows.h>
32 #define NTOS_MODE_USER
33 #include <ndk/ntndk.h>
34
35 #include <commctrl.h>
36 #include <stdio.h>
37 #include <tchar.h>
38 #include <stdlib.h>
39
40 #include <samlib/samlib.h>
41 #include <syssetup/syssetup.h>
42 #include <userenv.h>
43 #include <setupapi.h>
44
45 #include <shlobj.h>
46 #include <objidl.h>
47 #include <shlwapi.h>
48
49 #include "globals.h"
50 #include "resource.h"
51
52 #define VMWINST
53
54
55 /* GLOBALS ******************************************************************/
56
57 PSID DomainSid = NULL;
58 PSID AdminSid = NULL;
59
60 HINF hSysSetupInf = INVALID_HANDLE_VALUE;
61
62 /* FUNCTIONS ****************************************************************/
63
64 void
65 DebugPrint(char* fmt,...)
66 {
67 char buffer[512];
68 va_list ap;
69
70 va_start(ap, fmt);
71 vsprintf(buffer, fmt, ap);
72 va_end(ap);
73
74 strcat(buffer, "\nRebooting now!");
75 MessageBoxA(NULL,
76 buffer,
77 "ReactOS Setup",
78 MB_OK);
79 }
80
81
82 #ifdef VMWINST
83 static BOOL
84 RunVMWInstall(VOID)
85 {
86 PROCESS_INFORMATION ProcInfo;
87 STARTUPINFO si;
88 WCHAR InstallName[] = L"vmwinst.exe";
89
90 ZeroMemory(&si, sizeof(STARTUPINFO));
91 si.cb = sizeof(STARTUPINFO);
92
93 if(CreateProcess(NULL, InstallName, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS,
94 NULL, NULL, &si, &ProcInfo))
95 {
96 WaitForSingleObject(ProcInfo.hProcess, INFINITE);
97 CloseHandle(ProcInfo.hThread);
98 CloseHandle(ProcInfo.hProcess);
99 return TRUE;
100 }
101 return FALSE;
102 }
103 #endif
104
105
106 HRESULT CreateShellLink(LPCTSTR linkPath, LPCTSTR cmd, LPCTSTR arg, LPCTSTR dir, LPCTSTR iconPath, int icon_nr, LPCTSTR comment)
107 {
108 IShellLink* psl;
109 IPersistFile* ppf;
110 #ifndef _UNICODE
111 WCHAR buffer[MAX_PATH];
112 #endif /* _UNICODE */
113
114 HRESULT hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, (LPVOID*)&psl);
115
116 if (SUCCEEDED(hr))
117 {
118 hr = psl->lpVtbl->SetPath(psl, cmd);
119
120 if (arg)
121 {
122 hr = psl->lpVtbl->SetArguments(psl, arg);
123 }
124
125 if (dir)
126 {
127 hr = psl->lpVtbl->SetWorkingDirectory(psl, dir);
128 }
129
130 if (iconPath)
131 {
132 hr = psl->lpVtbl->SetIconLocation(psl, iconPath, icon_nr);
133 }
134
135 if (comment)
136 {
137 hr = psl->lpVtbl->SetDescription(psl, comment);
138 }
139
140 hr = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf);
141
142 if (SUCCEEDED(hr))
143 {
144 #ifdef _UNICODE
145 hr = ppf->lpVtbl->Save(ppf, linkPath, TRUE);
146 #else /* _UNICODE */
147 MultiByteToWideChar(CP_ACP, 0, linkPath, -1, buffer, MAX_PATH);
148
149 hr = ppf->lpVtbl->Save(ppf, buffer, TRUE);
150 #endif /* _UNICODE */
151
152 ppf->lpVtbl->Release(ppf);
153 }
154
155 psl->lpVtbl->Release(psl);
156 }
157
158 return hr;
159 }
160
161
162 static BOOL
163 CreateShortcut(int csidl, LPCTSTR folder, LPCTSTR linkName, LPCTSTR command, UINT nIdTitle)
164 {
165 TCHAR path[MAX_PATH];
166 TCHAR title[256];
167 LPTSTR p = path;
168
169 if (!SHGetSpecialFolderPath(0, path, csidl, TRUE))
170 return FALSE;
171
172 if (folder)
173 {
174 p = PathAddBackslash(p);
175 _tcscpy(p, folder);
176 }
177
178 p = PathAddBackslash(p);
179 _tcscpy(p, linkName);
180
181 if (!LoadString(hDllInstance, nIdTitle, title, 256))
182 return FALSE;
183
184 return SUCCEEDED(CreateShellLink(path, command, _T(""), NULL, NULL, 0, title));
185 }
186
187
188 static BOOL
189 CreateShortcutFolder(int csidl, UINT nID, LPTSTR name, int nameLen)
190 {
191 TCHAR path[MAX_PATH];
192 LPTSTR p;
193
194 if (!SHGetSpecialFolderPath(0, path, csidl, TRUE))
195 return FALSE;
196
197 if (!LoadString(hDllInstance, nID, name, nameLen))
198 return FALSE;
199
200 p = PathAddBackslash(path);
201 _tcscpy(p, name);
202
203 return CreateDirectory(path, NULL) || GetLastError()==ERROR_ALREADY_EXISTS;
204 }
205
206
207 static VOID
208 CreateRandomSid (PSID *Sid)
209 {
210 SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
211 LARGE_INTEGER SystemTime;
212 PULONG Seed;
213
214 NtQuerySystemTime (&SystemTime);
215 Seed = &SystemTime.u.LowPart;
216
217 RtlAllocateAndInitializeSid (&SystemAuthority,
218 4,
219 SECURITY_NT_NON_UNIQUE_RID,
220 RtlUniform (Seed),
221 RtlUniform (Seed),
222 RtlUniform (Seed),
223 SECURITY_NULL_RID,
224 SECURITY_NULL_RID,
225 SECURITY_NULL_RID,
226 SECURITY_NULL_RID,
227 Sid);
228 }
229
230
231 static VOID
232 AppendRidToSid (PSID *Dst,
233 PSID Src,
234 ULONG NewRid)
235 {
236 ULONG Rid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
237 UCHAR RidCount;
238 ULONG i;
239
240 RidCount = *RtlSubAuthorityCountSid (Src);
241
242 for (i = 0; i < RidCount; i++)
243 Rid[i] = *RtlSubAuthoritySid (Src, i);
244
245 if (RidCount < 8)
246 {
247 Rid[RidCount] = NewRid;
248 RidCount++;
249 }
250
251 RtlAllocateAndInitializeSid (RtlIdentifierAuthoritySid (Src),
252 RidCount,
253 Rid[0],
254 Rid[1],
255 Rid[2],
256 Rid[3],
257 Rid[4],
258 Rid[5],
259 Rid[6],
260 Rid[7],
261 Dst);
262 }
263
264 INT_PTR CALLBACK
265 RestartDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
266 {
267 switch(msg)
268 {
269 case WM_INITDIALOG:
270 SendDlgItemMessage(hWnd, IDC_RESTART_PROGRESS, PBM_SETRANGE, 0,
271 MAKELPARAM(0, 300));
272 SetTimer(hWnd, 1, 50, NULL);
273 return TRUE;
274
275 case WM_TIMER:
276 {
277 INT Position;
278 HWND hWndProgress;
279
280 hWndProgress = GetDlgItem(hWnd, IDC_RESTART_PROGRESS);
281 Position = SendMessage(hWndProgress, PBM_GETPOS, 0, 0);
282 if (Position == 300)
283 EndDialog(hWnd, 0);
284 else
285 SendMessage(hWndProgress, PBM_SETPOS, Position + 1, 0);
286 }
287 return TRUE;
288
289 case WM_COMMAND:
290 switch (wParam)
291 {
292 case IDOK:
293 case IDCANCEL:
294 EndDialog(hWnd, 0);
295 return TRUE;
296 }
297 break;
298 }
299
300 return FALSE;
301 }
302
303 static VOID
304 CreateTempDir(LPCWSTR VarName)
305 {
306 TCHAR szTempDir[MAX_PATH];
307 TCHAR szBuffer[MAX_PATH];
308 DWORD dwLength;
309 HKEY hKey;
310
311 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
312 _T("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"),
313 0,
314 KEY_ALL_ACCESS,
315 &hKey))
316 {
317 DebugPrint("Error: %lu\n", GetLastError());
318 return;
319 }
320
321 /* Get temp dir */
322 dwLength = MAX_PATH * sizeof(TCHAR);
323 if (RegQueryValueEx(hKey,
324 VarName,
325 NULL,
326 NULL,
327 (LPBYTE)szBuffer,
328 &dwLength))
329 {
330 DebugPrint("Error: %lu\n", GetLastError());
331 RegCloseKey(hKey);
332 return;
333 }
334
335 /* Expand it */
336 if (!ExpandEnvironmentStrings(szBuffer,
337 szTempDir,
338 MAX_PATH))
339 {
340 DebugPrint("Error: %lu\n", GetLastError());
341 RegCloseKey(hKey);
342 return;
343 }
344
345 /* Create profiles directory */
346 if (!CreateDirectory(szTempDir, NULL))
347 {
348 if (GetLastError() != ERROR_ALREADY_EXISTS)
349 {
350 DebugPrint("Error: %lu\n", GetLastError());
351 RegCloseKey(hKey);
352 return;
353 }
354 }
355
356 RegCloseKey(hKey);
357 }
358
359
360 BOOL
361 ProcessSysSetupInf(VOID)
362 {
363 INFCONTEXT InfContext;
364 TCHAR LineBuffer[256];
365 DWORD LineLength;
366
367 if (!SetupFindFirstLine(hSysSetupInf,
368 _T("DeviceInfsToInstall"),
369 NULL,
370 &InfContext))
371 {
372 return FALSE;
373 }
374
375 do
376 {
377 if (!SetupGetStringField(&InfContext,
378 0,
379 LineBuffer,
380 256,
381 &LineLength))
382 {
383 return FALSE;
384 }
385
386 if (!SetupDiInstallClass(NULL, LineBuffer, DI_QUIETINSTALL, NULL))
387 {
388 return FALSE;
389 }
390 }
391 while (SetupFindNextLine(&InfContext, &InfContext));
392
393 return TRUE;
394 }
395
396
397 DWORD STDCALL
398 InstallReactOS (HINSTANCE hInstance)
399 {
400 TCHAR sAccessories[256];
401
402 # if 0
403 OutputDebugStringA ("InstallReactOS() called\n");
404
405 if (!InitializeSetupActionLog (FALSE))
406 {
407 OutputDebugStringA ("InitializeSetupActionLog() failed\n");
408 }
409
410 LogItem (SYSSETUP_SEVERITY_INFORMATION,
411 L"ReactOS Setup starting");
412
413 LogItem (SYSSETUP_SEVERITY_FATAL_ERROR,
414 L"Buuuuuuaaaah!");
415
416 LogItem (SYSSETUP_SEVERITY_INFORMATION,
417 L"ReactOS Setup finished");
418
419 TerminateSetupActionLog ();
420 #endif
421 #if 0
422 UNICODE_STRING SidString;
423 #endif
424 ULONG LastError;
425
426 if (!InitializeProfiles ())
427 {
428 DebugPrint ("InitializeProfiles() failed\n");
429 return 0;
430 }
431
432 CoInitialize(NULL);
433
434 /* create desktop shortcuts */
435 CreateShortcut(CSIDL_DESKTOP, NULL, _T("Command Prompt.lnk"), _T("cmd.exe"), IDS_CMT_CMD);
436
437 /* create program startmenu shortcuts */
438 CreateShortcut(CSIDL_PROGRAMS, NULL, _T("winefile.lnk"), _T("winefile.exe"), IDS_CMT_WINEFILE);
439
440 /* create and fill Accessories subfolder */
441 if (CreateShortcutFolder(CSIDL_PROGRAMS, IDS_ACCESSORIES, sAccessories, 256)) {
442 //CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("Calculator.lnk"), _T("calc.exe"), IDS_CMT_CALC);
443 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("Command Prompt.lnk"), _T("cmd.exe"), IDS_CMT_CMD);
444 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("notepad.lnk"), _T("notepad.exe"), IDS_CMT_NOTEPAD);
445 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("explorer.lnk"), _T("explorer.exe"), IDS_CMT_EXPLORER);
446 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("regedit.lnk"), _T("regedit.exe"), IDS_CMT_REGEDIT);
447 }
448
449 CoUninitialize();
450
451 /* Create the semi-random Domain-SID */
452 CreateRandomSid (&DomainSid);
453 if (DomainSid == NULL)
454 {
455 DebugPrint ("Domain-SID creation failed!\n");
456 return 0;
457 }
458
459 #if 0
460 RtlConvertSidToUnicodeString (&SidString, DomainSid, TRUE);
461 DebugPrint ("Domain-SID: %wZ\n", &SidString);
462 RtlFreeUnicodeString (&SidString);
463 #endif
464
465 /* Initialize the Security Account Manager (SAM) */
466 if (!SamInitializeSAM ())
467 {
468 DebugPrint ("SamInitializeSAM() failed!\n");
469 RtlFreeSid (DomainSid);
470 return 0;
471 }
472
473 /* Set the Domain SID (aka Computer SID) */
474 if (!SamSetDomainSid (DomainSid))
475 {
476 DebugPrint ("SamSetDomainSid() failed!\n");
477 RtlFreeSid (DomainSid);
478 return 0;
479 }
480
481 /* Append the Admin-RID */
482 AppendRidToSid(&AdminSid, DomainSid, DOMAIN_USER_RID_ADMIN);
483
484 #if 0
485 RtlConvertSidToUnicodeString (&SidString, DomainSid, TRUE);
486 DebugPrint ("Admin-SID: %wZ\n", &SidString);
487 RtlFreeUnicodeString (&SidString);
488 #endif
489
490 /* Create the Administrator account */
491 if (!SamCreateUser(L"Administrator", L"", AdminSid))
492 {
493 /* Check what the error was.
494 * If the Admin Account already exists, then it means Setup
495 * wasn't allowed to finish properly. Instead of rebooting
496 * and not completing it, let it restart instead
497 */
498 LastError = GetLastError();
499 if (LastError != ERROR_USER_EXISTS)
500 {
501 DebugPrint("SamCreateUser() failed!\n");
502 RtlFreeSid(AdminSid);
503 RtlFreeSid(DomainSid);
504 return 0;
505 }
506 }
507
508 /* Create the Administrator profile */
509 if (!CreateUserProfileW(AdminSid, L"Administrator"))
510 {
511 DebugPrint("CreateUserProfileW() failed!\n");
512 RtlFreeSid(AdminSid);
513 RtlFreeSid(DomainSid);
514 return 0;
515 }
516
517 RtlFreeSid(AdminSid);
518 RtlFreeSid(DomainSid);
519
520 CreateTempDir(L"TEMP");
521 CreateTempDir(L"TMP");
522
523 hSysSetupInf = SetupOpenInfFileW(L"syssetup.inf",
524 NULL,
525 INF_STYLE_WIN4,
526 NULL);
527 if (hSysSetupInf == INVALID_HANDLE_VALUE)
528 {
529 DebugPrint("SetupOpenInfFileW() failed to open 'syssetup.inf' (Error: %lu)\n", GetLastError());
530 return 0;
531 }
532
533 if (!ProcessSysSetupInf())
534 {
535 DebugPrint("ProcessSysSetupInf() failed!\n");
536 return 0;
537 }
538
539 InstallWizard();
540
541 SetupCloseInfFile(hSysSetupInf);
542
543 #ifdef VMWINST
544 RunVMWInstall();
545 #endif
546
547 DialogBox(hDllInstance,
548 MAKEINTRESOURCE(IDD_RESTART),
549 NULL,
550 RestartDlgProc);
551
552 return 0;
553 }
554
555
556 /*
557 * @unimplemented
558 */
559 DWORD STDCALL
560 SetupChangeFontSize(HANDLE hWnd,
561 LPCWSTR lpszFontSize)
562 {
563 return FALSE;
564 }