0

How can I check whether my Java application is running as "SYSTEM"/"Local System" (as seen on Windows Service list)?

Windows Service List

I tried using this:

System.out.println("Running with user: " + System.getenv().get("USERDOMAIN") + "\\" + System.getenv().get("USERNAME"));

... but it seems to return DOMAIN\COMPUTERNAME according where the program is run. So it can be like DOMAIN1\COMPUTER1 and somewhere else it is FOO\SERVER451 and both still means "SYSTEM" account.

For background information, my Java application is wrapped to a Windows Service with 'Apache Commons Daemon Service Runner' and by default it will run as "Local System" (same way as in example image).

I really would want to simplify my code to print either SYSTEM or MYDOMAIN\JackTheUser depending on user type... Is there a way to do it with Java?


EDIT 20/12/02: This is what I have done meanwhile the SO army working to find the correct answer:

    Main:
    String username = System.getenv().get("USERNAME");
    String userdomain = System.getenv().get("USERDOMAIN");
    String servername = getComputerName();

    if (username.equalsIgnoreCase((servername + "$"))) {
        System.out.println("Running with user: 'Local System'("
                + userdomain + "\\" + username + ")");
    } else {
        System.out.println("Running with user: '" + userdomain + "\\"
                + username + "'");
    }
    
    Methods:
    private static String getComputerName() {
        Map<String, String> env = System.getenv();
        if (env.containsKey("COMPUTERNAME"))
            return env.get("COMPUTERNAME");
        else if (env.containsKey("HOSTNAME"))
            return env.get("HOSTNAME");
        else
            return "Unknown Host name";
    }

Prints:

Running with user: 'MYDOMAIN\jokkeri' or Running with user: 'Local System'(MYSERVER\SERVER_1$)

(not a perfect solution and I'm sure there are many occasions where it won't work but it's a starting point)


EDIT2 20/12/02: Some good information about SYSTEM account was found from this thread from superuser: https://superuser.com/questions/265216/windows-account-ending-with

Jokkeri
  • 1,001
  • 1
  • 13
  • 35
  • Suppose you do find out whether it is running as system or not, from within the program. What do you hope to do with this information? What problem are you actually trying to solve? – Karl Knechtel Dec 01 '20 at 06:53
  • @KarlKnechtel I would not say that I have 'a problem' but this would be an improvement for the application which have multiple 'agents'(java app) installed and I would like to gather statistics from which are running as SYSTEM and which are not. – Jokkeri Dec 01 '20 at 06:57

1 Answers1

2

That’s the best I can come up so far

private static final String APP_NAME = "Some App";

private static final Configuration CONFIG = new Configuration() {
  public @Override AppConfigurationEntry[] getAppConfigurationEntry(String name) {
      return name.equals(APP_NAME)?
          new AppConfigurationEntry[] { new AppConfigurationEntry(
              "com.sun.security.auth.module.NTLoginModule",
              LoginModuleControlFlag.REQUIRED, Collections.emptyMap())}:
          null;
  }
};

static final boolean DEBUG = true;

public static void main(String[] args) throws LoginException {
    LoginContext lc = new LoginContext(APP_NAME, null, null, CONFIG);
    lc.login();
    final Subject subject=lc.getSubject();
    boolean isSystem = false;
    try {
        for(Principal p: subject.getPrincipals()) {
            if(DEBUG) System.out.println(p);
            if(p.toString().equals("NTSidUserPrincipal: S-1-5-18")) {
                isSystem = true;
                if(DEBUG) System.out.println("\tit's SYSTEM");
            }
        }
    }
    finally { lc.logout(); }
}

As explained in this answer, SYSTEM is a set of permissions that can be attached to different accounts. The code iterates over all principals associated with the current account and tests for the well known SYSTEM.

But if you’re only interested in a printable user name, you may check for the NTUserPrincipal.

LoginContext lc = new LoginContext(APP_NAME, null, null, CONFIG);
lc.login();
final Subject subject=lc.getSubject();
try {
    String name = System.getProperty("user.name"); // just a fall-back
    for(Principal p: subject.getPrincipals()) {
        if(p.toString().startsWith("NTUserPrincipal: ")) {
            name = p.getName();
            break;
        }
    }
    System.out.println("Hello " + name);
}
finally { lc.logout(); }

If you can live with a direct dependency to the com.sun.security.auth package (or jdk.security.auth module in Java 9+), you can use the specific principal types directly

LoginContext lc = new LoginContext(APP_NAME, null, null, CONFIG);
lc.login();
final Subject subject=lc.getSubject();
try {
    boolean system = false;
    for(NTSidUserPrincipal p: subject.getPrincipals(NTSidUserPrincipal.class)) {
        if(p.getName().equals("S-1-5-18")) {
            system = true;
            break;
        }
    }
    Set<NTUserPrincipal> up = subject.getPrincipals(NTUserPrincipal.class);
    String name = up.isEmpty()?
        System.getProperty("user.name"): up.iterator().next().getName();

    System.out.println("Hello " + name+(system? " *": ""));
}
finally { lc.logout(); }
Holger
  • 285,553
  • 42
  • 434
  • 765