001
014
015 package com.liferay.portal.security.pacl.checker;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.util.GetterUtil;
020 import com.liferay.portal.kernel.util.StringPool;
021 import com.liferay.portal.kernel.util.Validator;
022
023 import java.net.InetAddress;
024 import java.net.UnknownHostException;
025
026 import java.security.Permission;
027
028 import java.util.HashMap;
029 import java.util.HashSet;
030 import java.util.Map;
031 import java.util.Set;
032
033
036 public class SocketChecker extends BaseChecker {
037
038 public void afterPropertiesSet() {
039 initAcceptHostsAndPorts();
040 initConnectHostsAndPorts();
041 initListenPorts();
042 }
043
044 public void checkPermission(Permission permission) {
045 String actions = permission.getActions();
046
047 String name = permission.getName();
048
049 int pos = name.indexOf(StringPool.COLON);
050
051 String host = "localhost";
052
053 if (pos != -1) {
054 host = name.substring(0, pos);
055 }
056
057 int port = GetterUtil.getInteger(name.substring(pos + 1));
058
059
060
061 if (port == -1) {
062 if (_log.isDebugEnabled()) {
063 _log.debug("Always allow resolving of host " + host);
064 }
065
066 return;
067 }
068
069 if (actions.contains(SOCKET_PERMISSION_ACCEPT)) {
070 if (!hasAccept(host, port)) {
071 throwSecurityException(
072 _log,
073 "Attempted to accept from host " + host + " on port " +
074 port);
075 }
076 }
077 else if (actions.contains(SOCKET_PERMISSION_CONNECT)) {
078 if (!hasConnect(host, port)) {
079 throwSecurityException(
080 _log,
081 "Attempted to connect to host " + host + " on port " +
082 port);
083 }
084 }
085 else if (actions.contains(SOCKET_PERMISSION_LISTEN)) {
086 if (!hasListen(port)) {
087 throwSecurityException(
088 _log, "Attempted to listen on port " + port);
089 }
090 }
091 }
092
093 protected boolean hasAccept(String host, int port) {
094 Set<Integer> ports = _acceptHostsAndPorts.get(host);
095
096 if (ports == null) {
097 return false;
098 }
099
100 return ports.contains(port);
101 }
102
103 protected boolean hasConnect(String host, int port) {
104 Set<Integer> ports = _connectHostsAndPorts.get(host);
105
106 if (ports == null) {
107 return false;
108 }
109
110 return ports.contains(port);
111 }
112
113 protected boolean hasListen(int port) {
114 return _listenPorts.contains(port);
115 }
116
117 protected void initAcceptHostsAndPorts() {
118 String[] networkParts = getPropertyArray(
119 "security-manager-sockets-accept");
120
121 for (String networkPart : networkParts) {
122 initHostsAndPorts(networkPart, true);
123 }
124 }
125
126 protected void initConnectHostsAndPorts() {
127 String[] networkParts = getPropertyArray(
128 "security-manager-sockets-connect");
129
130 for (String networkPart : networkParts) {
131 initHostsAndPorts(networkPart, false);
132 }
133 }
134
135 protected void initHostsAndPorts(String networkPart, boolean accept) {
136 String action = "accept";
137
138 if (!accept) {
139 action = "connect";
140 }
141
142 int pos = networkPart.indexOf(StringPool.COLON);
143
144 if (pos == -1) {
145 if (_log.isWarnEnabled()) {
146 _log.warn(
147 "Unable to determine socket " + action +
148 " host and port from " + networkPart +
149 " because it is missing a colon delimeter");
150 }
151
152 return;
153 }
154
155 String host = networkPart.substring(0, pos);
156
157 if (!Validator.isDomain(host)) {
158 if (_log.isWarnEnabled()) {
159 _log.warn(
160 "Socket " + action + " host " + host +
161 " is not a valid domain");
162 }
163
164 return;
165 }
166
167 String portString = networkPart.substring(pos + 1);
168
169 int port = GetterUtil.getInteger(portString);
170
171 if (port <= 0) {
172 if (_log.isWarnEnabled()) {
173 _log.warn(
174 "Socket " + action + " port " + portString +
175 " is less than or equal to 0");
176 }
177
178 return;
179 }
180
181 InetAddress[] inetAddresses = null;
182
183 try {
184 inetAddresses = InetAddress.getAllByName(host);
185 }
186 catch (UnknownHostException uhe) {
187 if (_log.isWarnEnabled()) {
188 _log.warn("Unable to resolve host " + host);
189 }
190
191 return;
192 }
193
194 Map<String, Set<Integer>> hostsAndPorts = _acceptHostsAndPorts;
195
196 if (!accept) {
197 hostsAndPorts = _connectHostsAndPorts;
198 }
199
200 for (InetAddress inetAddress : inetAddresses) {
201 Set<Integer> ports = hostsAndPorts.get(
202 inetAddress.getHostAddress());
203
204 if (ports == null) {
205 ports = new HashSet<Integer>();
206
207 if (_log.isDebugEnabled()) {
208 _log.debug(
209 "Allowing socket " + action + " host " + host +
210 " with IP " + inetAddress.getHostAddress() +
211 " on port " + port);
212 }
213
214 hostsAndPorts.put(inetAddress.getHostAddress(), ports);
215 }
216
217 ports.add(port);
218 }
219 }
220
221 protected void initListenPorts() {
222 String[] listenParts = getPropertyArray(
223 "security-manager-sockets-listen");
224
225 for (String listenPart : listenParts) {
226 initListenPorts(listenPart);
227 }
228 }
229
230 protected void initListenPorts(String listenPart) {
231 int pos = listenPart.indexOf(StringPool.DASH);
232
233 if (pos == -1) {
234 if (!Validator.isNumber(listenPart)) {
235 if (_log.isWarnEnabled()) {
236 _log.warn(
237 "Socket listen port " + listenPart +
238 " is not a number");
239 }
240
241 return;
242 }
243
244 int port = GetterUtil.getInteger(listenPart);
245
246 if (_log.isDebugEnabled()) {
247 _log.debug("Allowing socket listen port " + port);
248 }
249
250 _listenPorts.add(port);
251 }
252 else {
253 String portString1 = listenPart.substring(0, pos);
254 String portString2 = listenPart.substring(pos + 1);
255
256 if (!Validator.isNumber(portString1)) {
257 if (_log.isWarnEnabled()) {
258 _log.warn(
259 "Socket listen port " + portString1 +
260 " is not a number");
261 }
262
263 return;
264 }
265
266 if (!Validator.isNumber(portString2)) {
267 if (_log.isWarnEnabled()) {
268 _log.warn(
269 "Socket listen port " + portString2 +
270 " is not a number");
271 }
272
273 return;
274 }
275
276 int port1 = GetterUtil.getInteger(portString1);
277 int port2 = GetterUtil.getInteger(portString2);
278
279 if (port1 >= port2) {
280 if (_log.isWarnEnabled()) {
281 _log.warn(
282 "Socket listen port range " + listenPart +
283 " is invalid");
284 }
285
286 return;
287 }
288
289 for (int i = port1; i <= port2; i++) {
290 if (_log.isDebugEnabled()) {
291 _log.debug("Allowing socket listen port " + i);
292 }
293
294 _listenPorts.add(i);
295 }
296 }
297 }
298
299 private static Log _log = LogFactoryUtil.getLog(SocketChecker.class);
300
301 private Map<String, Set<Integer>> _acceptHostsAndPorts =
302 new HashMap<String, Set<Integer>>();
303 private Map<String, Set<Integer>> _connectHostsAndPorts =
304 new HashMap<String, Set<Integer>>();
305 private Set<Integer> _listenPorts = new HashSet<Integer>();
306
307 }