From 242c04003884489d59fd4fff995fb94dd9dfce41 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Tue, 7 Mar 2017 10:37:35 +0100 Subject: [PATCH] Use system property to detect if root is running the program Motivation: We forked a new process to detect if the program is run by root. We should better just use user.name system property Modifications: - Change PlatformDependent.isRoot0() to read the user.name system property to detect if root runs the program and rename it to maybeSuperUser0(). - Rename PlatformDependent.isRoot() to maybeSuperUser() and let it init directly in the static block Result: Less heavy way to detect if the program is run by root. --- .../util/internal/PlatformDependent.java | 119 ++---------------- .../io/netty/channel/AbstractChannel.java | 2 +- .../socket/DefaultDatagramChannelConfig.java | 2 +- 3 files changed, 14 insertions(+), 109 deletions(-) diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent.java b/common/src/main/java/io/netty/util/internal/PlatformDependent.java index 1ab54d4d17..530fba4610 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent.java @@ -15,7 +15,6 @@ */ package io.netty.util.internal; -import io.netty.util.CharsetUtil; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; import org.jctools.queues.MpscArrayQueue; @@ -27,13 +26,8 @@ import org.jctools.queues.atomic.SpscLinkedAtomicQueue; import org.jctools.util.Pow2; import org.jctools.util.UnsafeAccess; -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; import java.lang.reflect.Method; -import java.net.InetSocketAddress; -import java.net.ServerSocket; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.AccessController; @@ -73,7 +67,7 @@ public final class PlatformDependent { private static final boolean IS_ANDROID = isAndroid0(); private static final boolean IS_WINDOWS = isWindows0(); - private static volatile Boolean IS_ROOT; + private static final boolean MAYBE_SUPER_USER; private static final int JAVA_VERSION = javaVersion0(); @@ -157,6 +151,8 @@ public final class PlatformDependent { } DIRECT_MEMORY_LIMIT = maxDirectMemory; logger.debug("io.netty.maxDirectMemory: {} bytes", maxDirectMemory); + + MAYBE_SUPER_USER = maybeSuperUser0(); } /** @@ -174,18 +170,11 @@ public final class PlatformDependent { } /** - * Return {@code true} if the current user is root. Note that this method returns - * {@code false} if on Windows. + * Return {@code true} if the current user may be a super-user. Be aware that this is just an hint and so it may + * return false-positives. */ - public static boolean isRoot() { - if (IS_ROOT == null) { - synchronized (PlatformDependent.class) { - if (IS_ROOT == null) { - IS_ROOT = isRoot0(); - } - } - } - return IS_ROOT; + public static boolean maybeSuperUser() { + return MAYBE_SUPER_USER; } /** @@ -652,97 +641,13 @@ public final class PlatformDependent { return windows; } - private static boolean isRoot0() { + private static boolean maybeSuperUser0() { + String username = SystemPropertyUtil.get("user.name"); if (isWindows()) { - return false; + return "Administrator".equals(username); } - - String[] ID_COMMANDS = { "/usr/bin/id", "/bin/id", "/usr/xpg4/bin/id", "id"}; - Pattern UID_PATTERN = Pattern.compile("^(?:0|[1-9][0-9]*)$"); - for (String idCmd: ID_COMMANDS) { - Process p = null; - BufferedReader in = null; - String uid = null; - try { - p = Runtime.getRuntime().exec(new String[] { idCmd, "-u" }); - in = new BufferedReader(new InputStreamReader(p.getInputStream(), CharsetUtil.US_ASCII)); - uid = in.readLine(); - in.close(); - - for (;;) { - try { - int exitCode = p.waitFor(); - if (exitCode != 0) { - uid = null; - } - break; - } catch (InterruptedException e) { - // Ignore - } - } - } catch (Throwable ignored) { - // Failed to run the command. - uid = null; - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - // Ignore - } - } - if (p != null) { - try { - p.destroy(); - } catch (Exception e) { - // Android sometimes triggers an ErrnoException. - } - } - } - - if (uid != null && UID_PATTERN.matcher(uid).matches()) { - logger.debug("UID: {}", uid); - return "0".equals(uid); - } - } - - logger.debug("Could not determine the current UID using /usr/bin/id; attempting to bind at privileged ports."); - - Pattern PERMISSION_DENIED = Pattern.compile(".*(?:denied|not.*permitted).*"); - for (int i = 1023; i > 0; i --) { - ServerSocket ss = null; - try { - ss = new ServerSocket(); - ss.setReuseAddress(true); - ss.bind(new InetSocketAddress(i)); - if (logger.isDebugEnabled()) { - logger.debug("UID: 0 (succeded to bind at port {})", i); - } - return true; - } catch (Exception e) { - // Failed to bind. - // Check the error message so that we don't always need to bind 1023 times. - String message = e.getMessage(); - if (message == null) { - message = ""; - } - message = message.toLowerCase(); - if (PERMISSION_DENIED.matcher(message).matches()) { - break; - } - } finally { - if (ss != null) { - try { - ss.close(); - } catch (Exception e) { - // Ignore. - } - } - } - } - - logger.debug("UID: non-root (failed to bind at any privileged ports)"); - return false; + // Check for root and toor as some BSDs have a toor user that is basically the same as root. + return "root".equals(username) || "toor".equals(username); } private static int javaVersion0() { diff --git a/transport/src/main/java/io/netty/channel/AbstractChannel.java b/transport/src/main/java/io/netty/channel/AbstractChannel.java index 80763a5e99..7037539b04 100644 --- a/transport/src/main/java/io/netty/channel/AbstractChannel.java +++ b/transport/src/main/java/io/netty/channel/AbstractChannel.java @@ -486,7 +486,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha if (Boolean.TRUE.equals(config().getOption(ChannelOption.SO_BROADCAST)) && localAddress instanceof InetSocketAddress && !((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress() && - !PlatformDependent.isWindows() && !PlatformDependent.isRoot()) { + !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) { // Warn a user about the fact that a non-root user can't receive a // broadcast packet on *nix if the socket is bound on non-wildcard address. logger.warn( diff --git a/transport/src/main/java/io/netty/channel/socket/DefaultDatagramChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/DefaultDatagramChannelConfig.java index b6616fbd6f..eb3ec3dc10 100644 --- a/transport/src/main/java/io/netty/channel/socket/DefaultDatagramChannelConfig.java +++ b/transport/src/main/java/io/netty/channel/socket/DefaultDatagramChannelConfig.java @@ -158,7 +158,7 @@ public class DefaultDatagramChannelConfig extends DefaultChannelConfig implement // See: https://github.com/netty/netty/issues/576 if (broadcast && !javaSocket.getLocalAddress().isAnyLocalAddress() && - !PlatformDependent.isWindows() && !PlatformDependent.isRoot()) { + !PlatformDependent.isWindows() && !PlatformDependent.maybeSuperUser()) { // Warn a user about the fact that a non-root user can't receive a // broadcast packet on *nix if the socket is bound on non-wildcard address. logger.warn(