blob: c26a95ec6b9f3d958229d70128727f1a6e9c181c [file] [log] [blame]
Peter Qiu1810c012015-02-05 14:35:41 -08001// Copyright 2015 The Chromium OS 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 "apmanager/firewall_manager.h"
6
7#include <base/bind.h>
8#include <chromeos/dbus/service_constants.h>
9#include <chromeos/errors/error.h>
10
11using std::string;
12
13namespace apmanager {
14
15namespace {
16
17const uint16_t kDhcpServerPort = 67;
18const int kInvalidFd = -1;
19
20} // namespace
21
22FirewallManager::FirewallManager()
23 : lifeline_read_fd_(kInvalidFd),
24 lifeline_write_fd_(kInvalidFd) {}
25
26FirewallManager::~FirewallManager() {
27 if (lifeline_read_fd_ != kInvalidFd) {
28 close(lifeline_read_fd_);
29 close(lifeline_write_fd_);
30 }
31}
32
Peter Qiu943cf3a2015-02-24 10:59:17 -080033void FirewallManager::Init(const scoped_refptr<dbus::Bus>& bus) {
Peter Qiu1810c012015-02-05 14:35:41 -080034 CHECK(!permission_broker_proxy_) << "Already started";
35
36 if (!SetupLifelinePipe()) {
37 return;
38 }
39
40 permission_broker_proxy_.reset(
41 new org::chromium::PermissionBrokerProxy(
42 bus,
43 permission_broker::kPermissionBrokerServiceName));
44
45 // This will connect the name owner changed signal in DBus object proxy,
46 // The callback will be invoked as soon as service is avalilable. and will
47 // be cleared after it is invoked. So this will be an one time callback.
48 permission_broker_proxy_->GetObjectProxy()->WaitForServiceToBeAvailable(
49 base::Bind(&FirewallManager::OnServiceAvailable, base::Unretained(this)));
50
51 // This will continuously monitor the name owner of the service. However,
52 // it does not connect the name owner changed signal in DBus object proxy
53 // for some reason. In order to connect the name owner changed signal,
54 // either WaitForServiceToBeAvaiable or ConnectToSignal need to be invoked.
55 // Since we're not interested in any signals from the proxy,
56 // WaitForServiceToBeAvailable is used.
57 permission_broker_proxy_->GetObjectProxy()->SetNameOwnerChangedCallback(
58 base::Bind(&FirewallManager::OnServiceNameChanged,
59 base::Unretained(this)));
60}
61
Peter Qiu943cf3a2015-02-24 10:59:17 -080062void FirewallManager::RequestDHCPPortAccess(const std::string& interface) {
63 CHECK(permission_broker_proxy_) << "Proxy not initialized yet";
64 if (dhcp_access_interfaces_.find(interface) !=
65 dhcp_access_interfaces_.end()) {
66 LOG(ERROR) << "DHCP access already requested for interface: " << interface;
67 return;
68 }
69 RequestUdpPortAccess(interface, kDhcpServerPort);
70 dhcp_access_interfaces_.insert(interface);
71}
72
73void FirewallManager::ReleaseDHCPPortAccess(const std::string& interface) {
74 CHECK(permission_broker_proxy_) << "Proxy not initialized yet";
75 if (dhcp_access_interfaces_.find(interface) ==
76 dhcp_access_interfaces_.end()) {
77 LOG(ERROR) << "DHCP access has not been requested for interface: "
78 << interface;
79 return;
80 }
81 ReleaseUdpPortAccess(interface, kDhcpServerPort);
82 dhcp_access_interfaces_.erase(interface);
83}
84
Peter Qiu1810c012015-02-05 14:35:41 -080085bool FirewallManager::SetupLifelinePipe() {
86 if (lifeline_read_fd_ != kInvalidFd) {
87 LOG(ERROR) << "Lifeline pipe already created";
88 return false;
89 }
90
91 // Setup lifeline pipe.
92 int fds[2];
93 if (pipe(fds) != 0) {
94 PLOG(ERROR) << "Failed to create lifeline pipe";
95 return false;
96 }
97 lifeline_read_fd_ = fds[0];
98 lifeline_write_fd_ = fds[1];
99
100 return true;
101}
102
103void FirewallManager::OnServiceAvailable(bool service_available) {
104 LOG(INFO) << "FirewallManager::OnServiceAvailabe " << service_available;
105 // Nothing to be done if proxy service is not available.
106 if (!service_available) {
107 return;
108 }
Peter Qiu943cf3a2015-02-24 10:59:17 -0800109 RequestAllPortsAccess();
Peter Qiu1810c012015-02-05 14:35:41 -0800110}
111
112void FirewallManager::OnServiceNameChanged(const string& old_owner,
113 const string& new_owner) {
114 LOG(INFO) << "FirewallManager::OnServiceNameChanged old " << old_owner
115 << " new " << new_owner;
116 // Nothing to be done if no owner is attached to the proxy service.
117 if (new_owner.empty()) {
118 return;
119 }
Peter Qiu943cf3a2015-02-24 10:59:17 -0800120 RequestAllPortsAccess();
Peter Qiu1810c012015-02-05 14:35:41 -0800121}
122
Peter Qiu943cf3a2015-02-24 10:59:17 -0800123void FirewallManager::RequestAllPortsAccess() {
124 // Request access to DHCP port for all specified interfaces.
125 for (const auto& dhcp_interface : dhcp_access_interfaces_) {
126 RequestUdpPortAccess(dhcp_interface, kDhcpServerPort);
127 }
Peter Qiu1810c012015-02-05 14:35:41 -0800128}
129
Peter Qiu943cf3a2015-02-24 10:59:17 -0800130void FirewallManager::RequestUdpPortAccess(const string& interface,
131 uint16_t port) {
Peter Qiu1810c012015-02-05 14:35:41 -0800132 bool allowed = false;
133 // Pass the read end of the pipe to permission_broker, for it to monitor this
134 // process.
135 dbus::FileDescriptor fd(lifeline_read_fd_);
136 fd.CheckValidity();
137 chromeos::ErrorPtr error;
138 if (!permission_broker_proxy_->RequestUdpPortAccess(port,
Peter Qiu943cf3a2015-02-24 10:59:17 -0800139 interface,
Peter Qiu1810c012015-02-05 14:35:41 -0800140 fd,
141 &allowed,
142 &error)) {
Peter Qiu943cf3a2015-02-24 10:59:17 -0800143 LOG(ERROR) << "Failed to request UDP port access: "
Peter Qiu1810c012015-02-05 14:35:41 -0800144 << error->GetCode() << " " << error->GetMessage();
145 return;
146 }
147 if (!allowed) {
Peter Qiu943cf3a2015-02-24 10:59:17 -0800148 LOG(ERROR) << "Access request for UDP port " << port
149 << " on interface " << interface << " is denied";
150 return;
Peter Qiu1810c012015-02-05 14:35:41 -0800151 }
Peter Qiu943cf3a2015-02-24 10:59:17 -0800152 LOG(INFO) << "Access granted for UDP port " << port
153 << " on interface " << interface;;
154}
155
156void FirewallManager::ReleaseUdpPortAccess(const string& interface,
157 uint16_t port) {
158 chromeos::ErrorPtr error;
159 bool success;
160 if (!permission_broker_proxy_->ReleaseUdpPort(port,
161 interface,
162 &success,
163 &error)) {
164 LOG(ERROR) << "Failed to release UDP port access: "
165 << error->GetCode() << " " << error->GetMessage();
166 return;
167 }
168 if (!success) {
169 LOG(ERROR) << "Release request for UDP port " << port
170 << " on interface " << interface << " is denied";
171 return;
172 }
173 LOG(INFO) << "Access released for UDP port " << port
174 << " on interface " << interface;
Peter Qiu1810c012015-02-05 14:35:41 -0800175}
176
177} // namespace apmanager