Home | History | Annotate | Download | only in webservd
      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"
     38 using FirewallImpl = webservd::FirewalldFirewall;
     39 #else
     40 #include "webservd/permission_broker_firewall.h"
     41 using FirewallImpl = webservd::PermissionBrokerFirewall;
     42 #endif  // defined(__ANDROID__)
     43 
     44 using brillo::dbus_utils::AsyncEventSequencer;
     45 
     46 namespace {
     47 
     48 const char kDefaultConfigFilePath[] = "/etc/webservd/config";
     49 const char kServiceName[] = "org.chromium.WebServer";
     50 const char kRootServicePath[] = "/org/chromium/WebServer";
     51 #if !defined(__ANDROID__)
     52 const char kWebServerUserName[] = "webservd";
     53 const char kWebServerGroupName[] = "webservd";
     54 #endif  // !defined(__ANDROID__)
     55 
     56 class 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 
     85 int 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