1// Copyright 2015 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <signal.h>
16#include <sysexits.h>
17
18#include <string>
19
20#include <base/command_line.h>
21#include <base/files/file_util.h>
22#include <brillo/dbus/async_event_sequencer.h>
23#include <brillo/dbus/exported_object_manager.h>
24#include <brillo/daemons/dbus_daemon.h>
25#include <brillo/flag_helper.h>
26#if !defined(__ANDROID__)
27#include <brillo/minijail/minijail.h>
28#endif  // !defined(__ANDROID__)
29#include <brillo/syslog_logging.h>
30
31#include "webservd/config.h"
32#include "webservd/log_manager.h"
33#include "webservd/server.h"
34#include "webservd/utils.h"
35
36#if defined(__ANDROID__)
37#include "webservd/firewalld_firewall.h"
38using FirewallImpl = webservd::FirewalldFirewall;
39#else
40#include "webservd/permission_broker_firewall.h"
41using FirewallImpl = webservd::PermissionBrokerFirewall;
42#endif  // defined(__ANDROID__)
43
44using brillo::dbus_utils::AsyncEventSequencer;
45
46namespace {
47
48const char kDefaultConfigFilePath[] = "/etc/webservd/config";
49const char kServiceName[] = "org.chromium.WebServer";
50const char kRootServicePath[] = "/org/chromium/WebServer";
51#if !defined(__ANDROID__)
52const char kWebServerUserName[] = "webservd";
53const char kWebServerGroupName[] = "webservd";
54#endif  // !defined(__ANDROID__)
55
56class Daemon final : public brillo::DBusServiceDaemon {
57 public:
58  explicit Daemon(webservd::Config config)
59      : DBusServiceDaemon{kServiceName, kRootServicePath},
60        config_{std::move(config)} {}
61
62 protected:
63  void RegisterDBusObjectsAsync(AsyncEventSequencer* sequencer) override {
64    webservd::LogManager::Init(base::FilePath{config_.log_directory});
65    server_.reset(new webservd::Server{
66        object_manager_.get(), config_,
67        std::unique_ptr<webservd::FirewallInterface>{new FirewallImpl()}});
68    server_->RegisterAsync(
69        sequencer->GetHandler("Server.RegisterAsync() failed.", true));
70  }
71
72  void OnShutdown(int* /* return_code */) override {
73    server_.reset();
74  }
75
76 private:
77  webservd::Config config_;
78  std::unique_ptr<webservd::Server> server_;
79
80  DISALLOW_COPY_AND_ASSIGN(Daemon);
81};
82
83}  // namespace
84
85int main(int argc, char* argv[]) {
86  DEFINE_bool(log_to_stderr, false, "log trace messages to stderr as well");
87  DEFINE_string(config_path, "",
88                "path to a file containing server configuration");
89  DEFINE_bool(debug, false,
90              "return debug error information in web requests");
91  DEFINE_bool(ipv6, true, "enable IPv6 support");
92  brillo::FlagHelper::Init(argc, argv, "Brillo web server daemon");
93
94  // From libmicrohttpd documentation, section 1.5 SIGPIPE:
95  // ... portable code using MHD must install a SIGPIPE handler or explicitly
96  // block the SIGPIPE signal.
97  // This also applies to using pipes over D-Bus to pass request/response data
98  // to/from remote request handlers. We handle errors from write operations on
99  // sockets/pipes correctly, so SIGPIPE is just a pest.
100  signal(SIGPIPE, SIG_IGN);
101
102  int flags = brillo::kLogToSyslog;
103  if (FLAGS_log_to_stderr)
104    flags |= brillo::kLogToStderr;
105  brillo::InitLog(flags | brillo::kLogHeader);
106
107  webservd::Config config;
108  config.use_ipv6 = FLAGS_ipv6;
109  base::FilePath default_file_path{kDefaultConfigFilePath};
110  if (!FLAGS_config_path.empty()) {
111    // In tests, we'll override the board specific and default configurations
112    // with a test specific configuration.
113    webservd::LoadConfigFromFile(base::FilePath{FLAGS_config_path}, &config);
114  } else if (base::PathExists(default_file_path)) {
115    // Some boards have a configuration they will want to use to override
116    // our defaults.  Part of our interface is to look for this in a
117    // standard location.
118    CHECK(webservd::LoadConfigFromFile(default_file_path, &config));
119  } else {
120    webservd::LoadDefaultConfig(&config);
121  }
122
123  // For protocol handlers bound to specific network interfaces, we need root
124  // access to create those bound sockets. Do that here before we drop
125  // privileges.
126  for (auto& handler_config : config.protocol_handlers) {
127    if (!handler_config.interface_name.empty()) {
128      int socket_fd =
129          webservd::CreateNetworkInterfaceSocket(handler_config.interface_name);
130      if (socket_fd < 0) {
131        LOG(ERROR) << "Failed to create a socket for network interface "
132                   << handler_config.interface_name;
133        return EX_SOFTWARE;
134      }
135      handler_config.socket_fd = socket_fd;
136    }
137  }
138
139  config.use_debug = FLAGS_debug;
140  Daemon daemon{std::move(config)};
141
142  // TODO: Re-enable this for Android once minijail works with libcap-ng.
143#if !defined(__ANDROID__)
144  // Drop privileges and use 'webservd' user. We need to do this after Daemon
145  // object is constructed since it creates an instance of base::AtExitManager
146  // which is required for brillo::Minijail::GetInstance() to work.
147  brillo::Minijail* minijail_instance = brillo::Minijail::GetInstance();
148  minijail* jail = minijail_instance->New();
149  minijail_instance->DropRoot(jail, kWebServerUserName, kWebServerGroupName);
150  // Permissions needed for the daemon to allow it to bind to ports like TCP
151  // 80.
152  minijail_instance->UseCapabilities(jail, CAP_TO_MASK(CAP_NET_BIND_SERVICE));
153  minijail_enter(jail);
154  minijail_instance->Destroy(jail);
155#endif  // !defined(__ANDROID__)
156
157  return daemon.Run();
158}
159