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