]> cygwin.com Git - cygwin-apps/setup.git/blame - main.cc
2003-10-23 Jerry D. Hedden <jerry@hedden.us>
[cygwin-apps/setup.git] / main.cc
CommitLineData
adaa168a 1 /*
23c9e63c 2 * Copyright (c) 2000, Red Hat, Inc.
e46e15bf 3 * Copyright (c) 2003, Robert Collins <rbtcollins@hotmail.com>
23c9e63c
DD
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 * A copy of the GNU General Public License can be found at
11 * http://www.gnu.org/
12 *
13 * Written by DJ Delorie <dj@cygnus.com>
e46e15bf
RC
14 * Robert Collins <rbtcollins@hotmail.com>
15 *
23c9e63c
DD
16 *
17 */
18
19/* OK, here's how this works. Each of the steps needed for install -
20 dialogs, downloads, installs - are in their own files and have some
21 "do_*" function (prototype in dialog.h) and a resource id (IDD_* or
22 IDD_S_* in resource.h) for that step. Each step is responsible for
23 selecting the next step! See the NEXT macro in dialog.h. Note
24 that the IDD_S_* ids are fake; those are for steps that don't
25 really have a controlling dialog (some have progress dialogs, but
26 those don't count, although they could). Replace the IDD_S_* with
27 IDD_* if you create a real dialog for those steps. */
28
b24c88b3
RC
29#if 0
30static const char *cvsid =
31 "\n%%% $Id$\n";
32#endif
8507f105 33
23c9e63c 34#include "win32.h"
ab57ceaa 35#include <commctrl.h>
23c9e63c
DD
36
37#include <stdio.h>
89b1a15b 38#include <stdlib.h>
23c9e63c
DD
39#include "resource.h"
40#include "dialog.h"
41#include "state.h"
42#include "msg.h"
23c9e63c
DD
43#include "find.h"
44#include "mount.h"
9f4a0c62 45#include "LogFile.h"
7cc06fd3 46#include "version.h"
89b1a15b
DD
47
48#include "port.h"
ab57ceaa
RC
49#include "proppage.h"
50#include "propsheet.h"
51
52// Page class headers
53#include "splash.h"
f9e903a3 54#include "AntiVirus.h"
ab57ceaa
RC
55#include "source.h"
56#include "root.h"
57#include "localdir.h"
58#include "net.h"
59#include "site.h"
60#include "choose.h"
61#include "threebar.h"
62#include "desktop.h"
23c9e63c 63
6908b7d7 64#include "getopt++/GetOption.h"
f2ff9838 65#include "getopt++/BoolOption.h"
1be8f8fd 66
0df9be37
RC
67#include "UserSettings.h"
68
23c9e63c
DD
69int next_dialog;
70
71HINSTANCE hinstance;
72
f2ff9838
RC
73static BoolOption UnattendedOption (false, 'q', "quiet-mode", "Unattended setup mode");
74
acbae401
CV
75/* Maximum size of a SID on NT/W2K. */
76#define MAX_SID_LEN 40
77
78/* Computes the size of an ACL in relation to the number of ACEs it
79 should contain. */
80#define TOKEN_ACL_SIZE(cnt) (sizeof(ACL) + \
81 (cnt) * (sizeof(ACCESS_ALLOWED_ACE) + MAX_SID_LEN))
82
83#define iswinnt (GetVersion() < 0x80000000)
84
e46e15bf
RC
85namespace Setup {
86 class SIDWrapper {
87 public:
88 SIDWrapper();
89 /* Prevent synthetics. If assignment is needed, this should be refcounting */
90 SIDWrapper(SIDWrapper const &);
91 SIDWrapper&operator=(SIDWrapper const&);
92 ~SIDWrapper();
93 /* We could look at doing weird typcast overloads here,
94 but manual access is easier for now
95 */
96 PSID &theSID();
97 PSID const &theSID() const;
98 private:
99 PSID value;
100 };
101
102SIDWrapper::SIDWrapper() : value(NULL) {}
103SIDWrapper::~SIDWrapper()
104{
105 if (value)
106 FreeSid (value);
107}
108
109PSID &
110SIDWrapper::theSID()
111{
112 return value;
113}
114
115PSID const &
116SIDWrapper::theSID() const
117{
118 return value;
119}
120
121 class HANDLEWrapper {
122 public:
123 HANDLEWrapper();
124 /* Prevent synthetics. If assignment is needed, we should duphandles, or refcount */
125 HANDLEWrapper(HANDLEWrapper const &);
126 HANDLEWrapper&operator=(HANDLEWrapper const &);
127 ~HANDLEWrapper();
128 HANDLE &theHANDLE();
129 HANDLE const &theHANDLE() const;
130 private:
131 HANDLE value;
132 };
133
134HANDLEWrapper::HANDLEWrapper() : value (NULL) {}
135HANDLEWrapper::~HANDLEWrapper()
136{
137 if (value)
138 CloseHandle(value);
139}
140
141HANDLE &
142HANDLEWrapper::theHANDLE()
143{
144 return value;
145}
146
147HANDLE const &
148HANDLEWrapper::theHANDLE() const
149{
150 return value;
151}
152
153};
154
155class TokenGroupCollection {
156 public:
157 TokenGroupCollection(DWORD, Setup::HANDLEWrapper &);
158 ~TokenGroupCollection();
159 /* prevent synthetics */
160 TokenGroupCollection &operator=(TokenGroupCollection const &);
161 TokenGroupCollection (TokenGroupCollection const &);
162 bool find (Setup::SIDWrapper const &) const;
163 bool populated() const { return populated_;}
164 void populate();
165 private:
166 mutable bool populated_;
167 char *buffer;
168 DWORD bufferSize;
169 Setup::HANDLEWrapper &token;
170};
171
172TokenGroupCollection::TokenGroupCollection(DWORD aSize, Setup::HANDLEWrapper &aHandle) : populated_(false), buffer(new char[aSize]), bufferSize(aSize), token(aHandle)
173{
174}
175
176TokenGroupCollection::~TokenGroupCollection()
177{
178 if (buffer)
179 delete[] buffer;
180}
181
182void
183TokenGroupCollection::populate()
184{
185 if (!GetTokenInformation (token.theHANDLE(), TokenGroups, buffer, bufferSize, &bufferSize))
186 {
187 log (LOG_TIMESTAMP) << "GetTokenInformation() failed: " <<
188 GetLastError () << endLog;
189 return;
190 }
191 populated_ = true;
192}
193
194bool
195TokenGroupCollection::find (Setup::SIDWrapper const &aSID) const
196{
197 if (!populated())
198 return false;
199 TOKEN_GROUPS *groups = (TOKEN_GROUPS *) buffer;
200 for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
201 if (EqualSid(groups->Groups[pg].Sid, aSID.theSID()))
202 return true;
203 return false;
204}
205
206class NTSecurity
207{
208public:
209 static void NoteFailedAPI(String const &);
210 NTSecurity();
211 ~NTSecurity();
212 /* prevent synthetics */
213 NTSecurity &operator=(NTSecurity const&);
214 NTSecurity(NTSecurity const &);
215
216 void setDefaultSecurity();
217private:
218 void failed(bool const &);
219 bool const &failed() const;
220 void initialiseEveryOneSID();
221 void setDefaultDACL ();
222 Setup::SIDWrapper everyOneSID, administratorsSID, usid;
223 Setup::HANDLEWrapper token;
224 bool failed_;
c59b8da6
MB
225 struct {
226 PSID psid;
227 char buf[MAX_SID_LEN];
228 } osid;
229 DWORD size;
e46e15bf
RC
230};
231
232void
233set_default_sec()
234{
235 NTSecurity worker;
236 worker.setDefaultSecurity();
237}
238
239void
240NTSecurity::NoteFailedAPI(String const &api)
241{
242 log (LOG_TIMESTAMP) << api << "() failed: " << GetLastError () << endLog;
243}
244
245NTSecurity::NTSecurity() : everyOneSID (), administratorsSID(), usid(), token(), failed_(false)
246{}
247
248NTSecurity::~NTSecurity()
249{
250}
251
252void
253NTSecurity::failed(bool const &aBool)
254{
255 failed_ = aBool;
256}
257
258bool const &
259NTSecurity::failed() const
260{
261 return failed_;
262}
263
acbae401 264void
e46e15bf
RC
265NTSecurity::initialiseEveryOneSID()
266{
267 SID_IDENTIFIER_AUTHORITY sid_auth = { SECURITY_WORLD_SID_AUTHORITY };
268 if (!AllocateAndInitializeSid (&sid_auth, 1, 0, 0, 0, 0, 0, 0, 0, 0, &everyOneSID.theSID()))
269 {
270 NoteFailedAPI ("AllocateAndInitializeSid");
271 failed(true);
272 }
273}
274
275void
276NTSecurity::setDefaultDACL ()
acbae401
CV
277{
278 /* To assure that the created files have a useful ACL, the
b24c88b3
RC
279 default DACL in the process token is set to full access to
280 everyone. This applies to files and subdirectories created
281 in directories which don't propagate permissions to child
adaa168a
MB
282 objects.
283 To assure that the files group is meaningful, a token primary
284 group of None is changed to Users or Administrators. */
acbae401 285
e46e15bf
RC
286 initialiseEveryOneSID();
287 if (failed())
288 return;
289
acbae401
CV
290 /* Create a buffer which has enough room to contain the TOKEN_DEFAULT_DACL
291 structure plus an ACL with one ACE. */
e46e15bf
RC
292 size_t bufferSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
293 + GetLengthSid(everyOneSID.theSID()) - sizeof(DWORD);
294
295 std::auto_ptr<char> buf (new char[bufferSize]);
acbae401
CV
296
297 /* First initialize the TOKEN_DEFAULT_DACL structure. */
e46e15bf 298 PACL dacl = (PACL)buf.get();
acbae401
CV
299
300 /* Initialize the ACL for containing one ACE. */
e46e15bf 301 if (!InitializeAcl (dacl, bufferSize, ACL_REVISION))
acbae401 302 {
e46e15bf
RC
303 NoteFailedAPI ("InitializeAcl");
304 failed(true);
acbae401
CV
305 return;
306 }
307
acbae401 308 /* Create the ACE which grants full access to "Everyone" and store it
e46e15bf 309 in dacl. */
b24c88b3 310 if (!AddAccessAllowedAce
e46e15bf 311 (dacl, ACL_REVISION, GENERIC_ALL, everyOneSID.theSID()))
acbae401 312 {
e46e15bf
RC
313 NoteFailedAPI ("AddAccessAllowedAce");
314 failed(true);
315 return;
acbae401
CV
316 }
317
318 /* Get the processes access token. */
acbae401 319 if (!OpenProcessToken (GetCurrentProcess (),
e46e15bf 320 TOKEN_READ | TOKEN_ADJUST_DEFAULT, &token.theHANDLE()))
acbae401 321 {
e46e15bf
RC
322 NoteFailedAPI ("OpenProcessToken");
323 failed(true);
324 return;
acbae401
CV
325 }
326
327 /* Set the default DACL to the above computed ACL. */
e46e15bf
RC
328 if (!SetTokenInformation (token.theHANDLE(), TokenDefaultDacl, &dacl, bufferSize))
329 {
330 NoteFailedAPI ("SetTokenInformation");
331 failed(true);
332 }
333}
acbae401 334
e46e15bf
RC
335void
336NTSecurity::setDefaultSecurity ()
337{
adaa168a 338
e46e15bf
RC
339 setDefaultDACL();
340 if (failed())
341 return;
342
c59b8da6
MB
343 /* Get the user */
344 if (!GetTokenInformation (token.theHANDLE(), TokenUser, &osid,
345 sizeof osid, &size))
adaa168a 346 {
c59b8da6 347 NoteFailedAPI("GetTokenInformation");
e46e15bf 348 return;
adaa168a 349 }
c59b8da6
MB
350 /* Make it the owner */
351 if (!SetTokenInformation (token.theHANDLE(), TokenOwner, &osid,
352 sizeof osid))
adaa168a 353 {
c59b8da6 354 NoteFailedAPI("SetTokenInformation");
e46e15bf 355 return;
adaa168a 356 }
e46e15bf
RC
357
358 SID_IDENTIFIER_AUTHORITY sid_auth;
359 sid_auth = (SID_IDENTIFIER_AUTHORITY) { SECURITY_NT_AUTHORITY };
360 /* Get the SID for "Administrators" S-1-5-32-544 */
361 if (!AllocateAndInitializeSid (&sid_auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
362 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administratorsSID.theSID()))
363 {
364 NoteFailedAPI("AllocateAndInitializeSid");
365 return;
366 }
367 /* Get the SID for "Users" S-1-5-32-545 */
368 if (!AllocateAndInitializeSid (&sid_auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
369 DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &usid.theSID()))
adaa168a 370 {
e46e15bf
RC
371 NoteFailedAPI("AllocateAndInitializeSid");
372 return;
373 }
374 /* Get the token groups */
375 if (!GetTokenInformation (token.theHANDLE(), TokenGroups, NULL, 0, &size)
adaa168a 376 && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
e46e15bf
RC
377 {
378 NoteFailedAPI("GetTokenInformation");
379 return;
adaa168a 380 }
e46e15bf
RC
381 TokenGroupCollection ntGroups(size, token);
382 ntGroups.populate();
383 if (!ntGroups.populated())
384 return;
385 /* Set the default group to one of the above computed SID. */
386 PSID nsid = NULL;
387 if (ntGroups.find (usid))
388 {
389 nsid = usid.theSID();
390 log(LOG_TIMESTAMP) << "Changing gid to Users" << endLog;
391 }
392 else if (ntGroups.find (administratorsSID))
393 {
394 nsid = administratorsSID.theSID();
395 log(LOG_TIMESTAMP) << "Changing gid to Administrators" << endLog;
396 }
397 if (nsid && !SetTokenInformation (token.theHANDLE(), TokenPrimaryGroup, &nsid, sizeof nsid))
398 NoteFailedAPI ("SetTokenInformation");
acbae401
CV
399}
400
ab57ceaa
RC
401// Other threads talk to this page, so we need to have it externable.
402ThreeBarProgressPage Progress;
403
9f4a0c62
RC
404// This is a little ugly, but the decision about where to log occurs
405// after the source is set AND the root mount obtained
406// so we make the actual logger available to the appropriate routine(s).
a55c8f45 407LogFile *theLog;
9f4a0c62 408
45e01f23 409#ifndef __CYGWIN__
23c9e63c 410int WINAPI
1fd6d0a2 411WinMain (HINSTANCE h,
b24c88b3 412 HINSTANCE hPrevInstance, LPSTR command_line, int cmd_show)
23c9e63c 413{
8bb9dad9 414
23c9e63c 415 hinstance = h;
45e01f23
RC
416#else
417int
418main (int argc, char **argv)
419{
420 hinstance = GetModuleHandle (NULL);
421#endif
23c9e63c 422
9f4a0c62
RC
423 char *cwd=new char[_MAX_PATH];
424 GetCurrentDirectory (_MAX_PATH, cwd);
425 local_dir = String (cwd);
426 delete cwd;
427
15004270 428 LogSingleton::SetInstance (*(theLog = LogFile::createLogFile()));
a55c8f45
RC
429 theLog->setFile (LOG_BABBLE, local_dir + "/setup.log.full", false);
430 theLog->setFile (0, local_dir + "/setup.log", true);
9f4a0c62 431
9f4a0c62 432 log (LOG_PLAIN) << "Starting cygwin install, version " << version << endLog;
0df9be37
RC
433
434 UserSettings::Instance().loadAllSettings();
435
ab57ceaa 436 SplashPage Splash;
f9e903a3 437 AntiVirusPage AntiVirus;
ab57ceaa
RC
438 SourcePage Source;
439 RootPage Root;
440 LocalDirPage LocalDir;
441 NetPage Net;
442 SitePage Site;
443 ChooserPage Chooser;
444 DesktopSetupPage Desktop;
445 PropSheet MainWindow;
446
9f4a0c62 447 log (LOG_TIMESTAMP) << "Current Directory: " << local_dir << endLog;
89b1a15b 448
45e01f23
RC
449 // TODO: make an equivalent for __argv under cygwin.
450 char **_argv;
451#ifndef __CYGWIN__
ef465627 452 int argc;
45e01f23
RC
453// char **_argv;
454#ifndef __CYGWIN__
455 for (argc = 0, _argv = __argv; *_argv; _argv++)++argc;
456 _argv = __argv;
457#else
458// for (argc = 0, _argv = argv; *_argv; _argv++)++argc;
459 _argv = argv;
460#endif
461#else
462 _argv = argv;
463#endif
1be8f8fd 464
45e01f23 465 if (!GetOption::GetInstance().Process (argc,_argv))
a55c8f45 466 theLog->exit(1);
45e01f23 467// #endif
b24c88b3 468
f2ff9838
RC
469 unattended_mode = UnattendedOption;
470
adaa168a
MB
471 /* Set the default DACL and Group only on NT/W2K. 9x/ME has
472 no idea of access control lists and security at all. */
acbae401 473 if (iswinnt)
adaa168a 474 set_default_sec ();
acbae401 475
ab57ceaa
RC
476 // Initialize common controls
477 InitCommonControls ();
478
479 // Init window class lib
45e01f23 480 Window::SetAppInstance (hinstance);
ab57ceaa
RC
481
482 // Create pages
483 Splash.Create ();
f9e903a3 484 AntiVirus.Create ();
ab57ceaa
RC
485 Source.Create ();
486 Root.Create ();
487 LocalDir.Create ();
488 Net.Create ();
489 Site.Create ();
490 Chooser.Create ();
491 Progress.Create ();
492 Desktop.Create ();
493
494 // Add pages to sheet
495 MainWindow.AddPage (&Splash);
f9e903a3 496 MainWindow.AddPage (&AntiVirus);
ab57ceaa
RC
497 MainWindow.AddPage (&Source);
498 MainWindow.AddPage (&Root);
499 MainWindow.AddPage (&LocalDir);
500 MainWindow.AddPage (&Net);
501 MainWindow.AddPage (&Site);
502 MainWindow.AddPage (&Chooser);
503 MainWindow.AddPage (&Progress);
504 MainWindow.AddPage (&Desktop);
505
506 // Create the PropSheet main window
507 MainWindow.Create ();
23c9e63c 508
0df9be37
RC
509 // Clean exit.. save user options.
510 UserSettings::Instance().saveAllSettings();
511
a55c8f45 512 theLog->exit (0);
b24c88b3
RC
513 /* Keep gcc happy :} */
514 return 0;
23c9e63c 515}
This page took 0.091471 seconds and 5 git commands to generate.