1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/browser_main_gtk.h"
6
7#include <gtk/gtk.h>
8#include <sys/stat.h>
9#include <sys/types.h>
10#include <unistd.h>
11
12#include "base/command_line.h"
13#include "base/debug/debugger.h"
14#include "chrome/browser/browser_main_win.h"
15#include "chrome/browser/metrics/metrics_service.h"
16#include "chrome/browser/ui/browser_list.h"
17#include "chrome/common/chrome_switches.h"
18#include "content/browser/renderer_host/render_sandbox_host_linux.h"
19#include "content/browser/zygote_host_linux.h"
20#include "content/common/result_codes.h"
21#include "grit/chromium_strings.h"
22#include "grit/generated_resources.h"
23#include "ui/base/l10n/l10n_util.h"
24#include "ui/base/resource/resource_bundle.h"
25#include "ui/base/x/x11_util.h"
26#include "ui/base/x/x11_util_internal.h"
27#include "ui/gfx/gtk_util.h"
28
29#if defined(USE_NSS)
30#include "crypto/nss_util.h"
31#endif
32
33#if defined(USE_LINUX_BREAKPAD)
34#include "chrome/app/breakpad_linux.h"
35#endif
36
37namespace {
38
39// Indicates that we're currently responding to an IO error (by shutting down).
40bool g_in_x11_io_error_handler = false;
41
42int BrowserX11ErrorHandler(Display* d, XErrorEvent* error) {
43  if (!g_in_x11_io_error_handler)
44    MessageLoop::current()->PostTask(
45        FROM_HERE,
46        NewRunnableFunction(ui::LogErrorEventDescription, d, *error));
47  return 0;
48}
49
50int BrowserX11IOErrorHandler(Display* d) {
51  // If there's an IO error it likely means the X server has gone away
52  if (!g_in_x11_io_error_handler) {
53    g_in_x11_io_error_handler = true;
54    LOG(ERROR) << "X IO Error detected";
55    BrowserList::SessionEnding();
56  }
57
58  return 0;
59}
60
61}  // namespace
62
63void BrowserMainPartsGtk::PreEarlyInitialization() {
64  DetectRunningAsRoot();
65
66  BrowserMainPartsPosix::PreEarlyInitialization();
67
68  SetupSandbox();
69
70#if defined(USE_NSS)
71  // We want to be sure to init NSPR on the main thread.
72  crypto::EnsureNSPRInit();
73#endif
74}
75
76void BrowserMainPartsGtk::DetectRunningAsRoot() {
77  if (geteuid() == 0) {
78    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
79    if (!parsed_command_line().HasSwitch(switches::kUserDataDir))
80      return;
81
82    gfx::GtkInitFromCommandLine(command_line);
83
84    // Get just enough of our resource machinery up so we can extract the
85    // locale appropriate string. Note that the GTK implementation ignores the
86    // passed in parameter and checks the LANG environment variables instead.
87    ResourceBundle::InitSharedInstance("");
88
89    std::string message = l10n_util::GetStringFUTF8(
90            IDS_REFUSE_TO_RUN_AS_ROOT,
91            l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
92    GtkWidget* dialog = gtk_message_dialog_new(
93        NULL,
94        static_cast<GtkDialogFlags>(0),
95        GTK_MESSAGE_ERROR,
96        GTK_BUTTONS_CLOSE,
97        "%s",
98        message.c_str());
99
100    LOG(ERROR) << "Startup refusing to run as root.";
101    message = l10n_util::GetStringFUTF8(
102        IDS_REFUSE_TO_RUN_AS_ROOT_2,
103        l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
104    gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
105                                             "%s",
106                                             message.c_str());
107
108    message = l10n_util::GetStringUTF8(IDS_PRODUCT_NAME);
109    gtk_window_set_title(GTK_WINDOW(dialog), message.c_str());
110
111    gtk_dialog_run(GTK_DIALOG(dialog));
112    gtk_widget_destroy(dialog);
113    exit(EXIT_FAILURE);
114  }
115}
116
117void BrowserMainPartsGtk::SetupSandbox() {
118  // TODO(evanm): move this into SandboxWrapper; I'm just trying to move this
119  // code en masse out of chrome_main for now.
120  const char* sandbox_binary = NULL;
121  struct stat st;
122
123  // In Chromium branded builds, developers can set an environment variable to
124  // use the development sandbox. See
125  // http://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment
126  if (stat("/proc/self/exe", &st) == 0 && st.st_uid == getuid())
127    sandbox_binary = getenv("CHROME_DEVEL_SANDBOX");
128
129#if defined(LINUX_SANDBOX_PATH)
130  if (!sandbox_binary)
131    sandbox_binary = LINUX_SANDBOX_PATH;
132#endif
133
134  std::string sandbox_cmd;
135  if (sandbox_binary && !parsed_command_line().HasSwitch(switches::kNoSandbox))
136    sandbox_cmd = sandbox_binary;
137
138  // Tickle the sandbox host and zygote host so they fork now.
139  RenderSandboxHostLinux* shost = RenderSandboxHostLinux::GetInstance();
140  shost->Init(sandbox_cmd);
141  ZygoteHost* zhost = ZygoteHost::GetInstance();
142  zhost->Init(sandbox_cmd);
143}
144
145void DidEndMainMessageLoop() {
146}
147
148void RecordBreakpadStatusUMA(MetricsService* metrics) {
149#if defined(USE_LINUX_BREAKPAD)
150  metrics->RecordBreakpadRegistration(IsCrashReporterEnabled());
151#else
152  metrics->RecordBreakpadRegistration(false);
153#endif
154  metrics->RecordBreakpadHasDebugger(base::debug::BeingDebugged());
155}
156
157void WarnAboutMinimumSystemRequirements() {
158  // Nothing to warn about on GTK right now.
159}
160
161void RecordBrowserStartupTime() {
162  // Not implemented on GTK for now.
163}
164
165// From browser_main_win.h, stubs until we figure out the right thing...
166
167int DoUninstallTasks(bool chrome_still_running) {
168  return ResultCodes::NORMAL_EXIT;
169}
170
171int HandleIconsCommands(const CommandLine &parsed_command_line) {
172  return 0;
173}
174
175bool CheckMachineLevelInstall() {
176  return false;
177}
178
179void PrepareRestartOnCrashEnviroment(const CommandLine &parsed_command_line) {
180}
181
182void SetBrowserX11ErrorHandlers() {
183  // Set up error handlers to make sure profile gets written if X server
184  // goes away.
185  ui::SetX11ErrorHandlers(BrowserX11ErrorHandler, BrowserX11IOErrorHandler);
186}
187
188#if !defined(OS_CHROMEOS)
189// static
190BrowserMainParts* BrowserMainParts::CreateBrowserMainParts(
191    const MainFunctionParams& parameters) {
192  return new BrowserMainPartsGtk(parameters);
193}
194#endif
195