]> cygwin.com Git - cygwin-apps/setup.git/blob - main.cc
2003-02-28 Max Bowsher <maxb@ukf.net>
[cygwin-apps/setup.git] / main.cc
1 /*
2 * Copyright (c) 2000, Red Hat, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by DJ Delorie <dj@cygnus.com>
13 *
14 */
15
16 /* OK, here's how this works. Each of the steps needed for install -
17 dialogs, downloads, installs - are in their own files and have some
18 "do_*" function (prototype in dialog.h) and a resource id (IDD_* or
19 IDD_S_* in resource.h) for that step. Each step is responsible for
20 selecting the next step! See the NEXT macro in dialog.h. Note
21 that the IDD_S_* ids are fake; those are for steps that don't
22 really have a controlling dialog (some have progress dialogs, but
23 those don't count, although they could). Replace the IDD_S_* with
24 IDD_* if you create a real dialog for those steps. */
25
26 #if 0
27 static const char *cvsid =
28 "\n%%% $Id$\n";
29 #endif
30
31 #include "win32.h"
32 #include <commctrl.h>
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include "resource.h"
37 #include "dialog.h"
38 #include "state.h"
39 #include "msg.h"
40 #include "find.h"
41 #include "mount.h"
42 #include "LogFile.h"
43 #include "version.h"
44
45 #include "port.h"
46 #include "proppage.h"
47 #include "propsheet.h"
48
49 // Page class headers
50 #include "splash.h"
51 #include "AntiVirus.h"
52 #include "source.h"
53 #include "root.h"
54 #include "localdir.h"
55 #include "net.h"
56 #include "site.h"
57 #include "choose.h"
58 #include "threebar.h"
59 #include "desktop.h"
60
61 #include "getopt++/GetOption.h"
62 #include "getopt++/BoolOption.h"
63
64 int next_dialog;
65
66 HINSTANCE hinstance;
67
68 static BoolOption UnattendedOption (false, 'q', "quiet-mode", "Unattended setup mode");
69
70 /* Maximum size of a SID on NT/W2K. */
71 #define MAX_SID_LEN 40
72
73 /* Computes the size of an ACL in relation to the number of ACEs it
74 should contain. */
75 #define TOKEN_ACL_SIZE(cnt) (sizeof(ACL) + \
76 (cnt) * (sizeof(ACCESS_ALLOWED_ACE) + MAX_SID_LEN))
77
78 #define iswinnt (GetVersion() < 0x80000000)
79
80 void
81 set_default_sec ()
82 {
83 /* To assure that the created files have a useful ACL, the
84 default DACL in the process token is set to full access to
85 everyone. This applies to files and subdirectories created
86 in directories which don't propagate permissions to child
87 objects.
88 To assure that the files group is meaningful, a token primary
89 group of None is changed to Users or Administrators. */
90
91 /* Create a buffer which has enough room to contain the TOKEN_DEFAULT_DACL
92 structure plus an ACL with one ACE. */
93 char buf[sizeof (TOKEN_DEFAULT_DACL) + TOKEN_ACL_SIZE (1)];
94
95 /* First initialize the TOKEN_DEFAULT_DACL structure. */
96 PTOKEN_DEFAULT_DACL dacl = (PTOKEN_DEFAULT_DACL) buf;
97 dacl->DefaultDacl = (PACL) (buf + sizeof *dacl);
98
99 /* Initialize the ACL for containing one ACE. */
100 if (!InitializeAcl (dacl->DefaultDacl, TOKEN_ACL_SIZE (1), ACL_REVISION))
101 {
102 log (LOG_TIMESTAMP) << "InitializeAcl() failed: " << GetLastError ()
103 << endLog;
104 return;
105 }
106
107 PSID esid = NULL, asid = NULL, usid = NULL;
108 HANDLE token = NULL;
109 struct {
110 PSID psid;
111 char buf[MAX_SID_LEN];
112 } gsid;
113 char lsid[MAX_SID_LEN];
114 char compname[MAX_COMPUTERNAME_LENGTH + 1];
115 char domain[MAX_COMPUTERNAME_LENGTH + 1];
116 DWORD size;
117
118 SID_IDENTIFIER_AUTHORITY sid_auth = { SECURITY_WORLD_SID_AUTHORITY };
119 if (!AllocateAndInitializeSid (&sid_auth, 1, 0, 0, 0, 0, 0, 0, 0, 0, &esid))
120 {
121 log (LOG_TIMESTAMP) << "AllocateAndInitializeSid() failed: " <<
122 GetLastError () << endLog;
123 goto out;
124 }
125
126 /* Create the ACE which grants full access to "Everyone" and store it
127 in dacl->DefaultDacl. */
128 if (!AddAccessAllowedAce
129 (dacl->DefaultDacl, ACL_REVISION, GENERIC_ALL, esid))
130 {
131 log (LOG_TIMESTAMP) << "AddAccessAllowedAce() failed: %lu" <<
132 GetLastError () << endLog;
133 goto out;
134 }
135
136 /* Get the processes access token. */
137 if (!OpenProcessToken (GetCurrentProcess (),
138 TOKEN_READ | TOKEN_ADJUST_DEFAULT, &token))
139 {
140 log (LOG_TIMESTAMP) << "OpenProcessToken() failed: " <<
141 GetLastError () << endLog;
142 goto out;
143 }
144
145 /* Set the default DACL to the above computed ACL. */
146 if (!SetTokenInformation (token, TokenDefaultDacl, dacl, sizeof buf))
147 log (LOG_TIMESTAMP) << "OpenProcessToken() failed: " <<
148 GetLastError () << endLog;
149
150
151 /* Get the default group */
152 if (!GetTokenInformation (token, TokenPrimaryGroup, &gsid, sizeof gsid, &size))
153 {
154 log (LOG_TIMESTAMP) << "GetTokenInformation() failed: " <<
155 GetLastError () << endLog;
156 goto out;
157 }
158
159 /* Get the computer name */
160 if (!GetComputerName (compname, (size = sizeof compname, &size)))
161 {
162 log (LOG_TIMESTAMP) << "GetComputerName() failed: " <<
163 GetLastError () << endLog;
164 goto out;
165 }
166
167 /* Get the local domain SID */
168 SID_NAME_USE use;
169 DWORD sz;
170 if (!LookupAccountName (NULL, compname, lsid, (size = sizeof lsid, &size),
171 domain, (sz = sizeof domain, &sz), &use))
172 {
173 log (LOG_TIMESTAMP) << "LookupAccountName() failed: " <<
174 GetLastError () << endLog;
175 goto out;
176 }
177
178 /* Create the None SID from the domain SID.
179 On NT the last subauthority of a domain is -1 and it is replaced by the RID.
180 On other systems the RID is appended. */
181 sz = *GetSidSubAuthorityCount (lsid);
182 if (*GetSidSubAuthority (lsid, sz -1) != (DWORD) -1)
183 *GetSidSubAuthorityCount (lsid) = ++sz;
184 *GetSidSubAuthority (lsid, sz -1) = DOMAIN_GROUP_RID_USERS;
185
186 /* See if the group is None */
187 if (EqualSid (gsid.psid, lsid))
188 {
189 bool isadmins = false, isusers = false;
190 sid_auth = (SID_IDENTIFIER_AUTHORITY) { SECURITY_NT_AUTHORITY };
191 /* Get the SID for "Administrators" S-1-5-32-544 */
192 if (!AllocateAndInitializeSid (&sid_auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
193 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &asid))
194 {
195 log (LOG_TIMESTAMP) << "AllocateAndInitializeSid() failed: " <<
196 GetLastError () << endLog;
197 goto out;
198 }
199 /* Get the SID for "Users" S-1-5-32-545 */
200 if (!AllocateAndInitializeSid (&sid_auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
201 DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &usid))
202 {
203 log (LOG_TIMESTAMP) << "AllocateAndInitializeSid() failed: " <<
204 GetLastError () << endLog;
205 goto out;
206 }
207 /* Get the token groups */
208 if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size)
209 && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
210 {
211 log (LOG_TIMESTAMP) << "GetTokenInformation() failed: " <<
212 GetLastError () << endLog;
213 goto out;
214 }
215 else
216 {
217 char buf[size];
218 TOKEN_GROUPS *groups = (TOKEN_GROUPS *) buf;
219
220 if (!GetTokenInformation (token, TokenGroups, buf, size, &size))
221 {
222 log (LOG_TIMESTAMP) << "GetTokenInformation() failed: " <<
223 GetLastError () << endLog;
224 goto out;
225 }
226 else
227 /* See if admins or users is present */
228 for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
229 {
230 isadmins = isadmins || EqualSid(groups->Groups[pg].Sid, asid);
231 isusers = isusers || EqualSid(groups->Groups[pg].Sid, usid);
232 }
233 }
234 /* Set the default group to one of the above computed SID. */
235 PSID nsid = NULL;
236 if (isusers)
237 {
238 nsid = usid;
239 log(LOG_TIMESTAMP) << "Changing gid to Users" << endLog;
240 }
241 else if (isadmins)
242 {
243 nsid = asid;
244 log(LOG_TIMESTAMP) << "Changing gid to Administrators" << endLog;
245 }
246 if (nsid && !SetTokenInformation (token, TokenPrimaryGroup, &nsid, sizeof nsid))
247 log (LOG_TIMESTAMP) << "SetTokenInformation() failed: " <<
248 GetLastError () << endLog;
249 }
250 out:
251 /* Close token handle. */
252 if (token)
253 CloseHandle (token);
254
255 /* Free memory occupied by the SIDs. */
256 if (esid)
257 FreeSid (esid);
258 if (asid)
259 FreeSid (asid);
260 if (usid)
261 FreeSid (usid);
262 }
263
264 // Other threads talk to this page, so we need to have it externable.
265 ThreeBarProgressPage Progress;
266
267 // This is a little ugly, but the decision about where to log occurs
268 // after the source is set AND the root mount obtained
269 // so we make the actual logger available to the appropriate routine(s).
270 LogFile *theLog;
271
272 #ifndef __CYGWIN__
273 int WINAPI
274 WinMain (HINSTANCE h,
275 HINSTANCE hPrevInstance, LPSTR command_line, int cmd_show)
276 {
277
278 hinstance = h;
279 #else
280 int
281 main (int argc, char **argv)
282 {
283 hinstance = GetModuleHandle (NULL);
284 #endif
285
286 char *cwd=new char[_MAX_PATH];
287 GetCurrentDirectory (_MAX_PATH, cwd);
288 local_dir = String (cwd);
289 delete cwd;
290
291 LogSingleton::SetInstance (*(theLog = LogFile::createLogFile()));
292 theLog->setFile (LOG_BABBLE, local_dir + "/setup.log.full", false);
293 theLog->setFile (0, local_dir + "/setup.log", true);
294
295 next_dialog = IDD_SPLASH;
296
297 log (LOG_PLAIN) << "Starting cygwin install, version " << version << endLog;
298
299 SplashPage Splash;
300 AntiVirusPage AntiVirus;
301 SourcePage Source;
302 RootPage Root;
303 LocalDirPage LocalDir;
304 NetPage Net;
305 SitePage Site;
306 ChooserPage Chooser;
307 DesktopSetupPage Desktop;
308 PropSheet MainWindow;
309
310 log (LOG_TIMESTAMP) << "Current Directory: " << local_dir << endLog;
311
312 // TODO: make an equivalent for __argv under cygwin.
313 char **_argv;
314 #ifndef __CYGWIN__
315 int argc;
316 // char **_argv;
317 #ifndef __CYGWIN__
318 for (argc = 0, _argv = __argv; *_argv; _argv++)++argc;
319 _argv = __argv;
320 #else
321 // for (argc = 0, _argv = argv; *_argv; _argv++)++argc;
322 _argv = argv;
323 #endif
324 #else
325 _argv = argv;
326 #endif
327
328 if (!GetOption::GetInstance().Process (argc,_argv))
329 theLog->exit(1);
330 // #endif
331
332 unattended_mode = UnattendedOption;
333
334 /* Set the default DACL and Group only on NT/W2K. 9x/ME has
335 no idea of access control lists and security at all. */
336 if (iswinnt)
337 set_default_sec ();
338
339 // Initialize common controls
340 InitCommonControls ();
341
342 // Init window class lib
343 Window::SetAppInstance (hinstance);
344
345 // Create pages
346 Splash.Create ();
347 AntiVirus.Create ();
348 Source.Create ();
349 Root.Create ();
350 LocalDir.Create ();
351 Net.Create ();
352 Site.Create ();
353 Chooser.Create ();
354 Progress.Create ();
355 Desktop.Create ();
356
357 // Add pages to sheet
358 MainWindow.AddPage (&Splash);
359 MainWindow.AddPage (&AntiVirus);
360 MainWindow.AddPage (&Source);
361 MainWindow.AddPage (&Root);
362 MainWindow.AddPage (&LocalDir);
363 MainWindow.AddPage (&Net);
364 MainWindow.AddPage (&Site);
365 MainWindow.AddPage (&Chooser);
366 MainWindow.AddPage (&Progress);
367 MainWindow.AddPage (&Desktop);
368
369 // Create the PropSheet main window
370 MainWindow.Create ();
371
372 theLog->exit (0);
373 /* Keep gcc happy :} */
374 return 0;
375 }
This page took 0.056771 seconds and 6 git commands to generate.