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