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