- Как с помощью Java выполнить Shell-команду
- Зависимость операционной системы
- Ввод и вывод
- Runtime.exec()
- ProcessBuilder
- Заключение
- How to pass the user and pwd via the runtime.exec() in java
- How to pass the user and pwd via the runtime.exec() in java
- Executing cd and pwd in java program
- Change AD Password with Java
Как с помощью Java выполнить Shell-команду
В этом руководстве мы рассмотрим два способа выполнения shell -команд из программы на Java . Первый способ – использовать класс Runtime и вызвать его метод exec . Второй (более гибкий способ) – создать экземпляр класса ProcessBuilder .
Зависимость операционной системы
Сначала нужно определить операционную систему, на которой работает наша JVM . В Windows необходимо запустить команду в качестве аргумента оболочки cmd.exe, а в остальных ОС мы будем использовать стандартную оболочку sh:
boolean isWindows = System.getProperty("os.name") .toLowerCase().startsWith("windows");
Ввод и вывод
Также нужно подключиться к входным и выходным потокам нашего процесса. По крайней мере, нужно получить выходные данные, иначе процесс зависнет.
Реализуем класс StreamGobbler, который использует InputStream :
private static class StreamGobbler implements Runnable < private InputStream inputStream; private Consumerconsumer; public StreamGobbler(InputStream inputStream, Consumer consumer) < this.inputStream = inputStream; this.consumer = consumer; >@Override public void run() < new BufferedReader(new InputStreamReader(inputStream)).lines() .forEach(consumer); >>
Примечание. Этот класс реализует интерфейс Runnable , а это означает, что он может быть выполнен любым исполнителем.
Runtime.exec()
Метод Runtime.exec() — это простой, но недостаточно гибкий способ создания нового подпроцесса .
В следующем примере мы запросим список пользователей из локальной директории и выведем его в консоли:
String homeDirectory = System.getProperty("user.home"); Process process; if (isWindows) < process = Runtime.getRuntime() .exec(String.format("cmd.exe /c dir %s", homeDirectory)); >else < process = Runtime.getRuntime() .exec(String.format("sh -c ls %s", homeDirectory)); >StreamGobbler streamGobbler = new StreamGobbler(process.getInputStream(), System.out::println); Executors.newSingleThreadExecutor().submit(streamGobbler); int exitCode = process.waitFor(); assert exitCode == 0;
ProcessBuilder
Класс ProcessBuilder является более гибким в использовании, чем Runtime. Он позволяет настраивать целый ряд параметров.
- изменить рабочий каталог, в котором работает shell-команда,
- перенаправить потоки ввода и вывода;
- наследовать их в потоках текущего процесса JVM, используя builder.inheritIO().
ProcessBuilder builder = new ProcessBuilder(); if (isWindows) < builder.command("cmd.exe", "/c", "dir"); >else < builder.command("sh", "-c", "ls"); >builder.directory(new File(System.getProperty("user.home"))); Process process = builder.start(); StreamGobbler streamGobbler = new StreamGobbler(process.getInputStream(), System.out::println); Executors.newSingleThreadExecutor().submit(streamGobbler); int exitCode = process.waitFor(); assert exitCode == 0;
Заключение
Shell команды в Java можно выполнять двумя различными способами. Но если нужно настроить выполнение созданного процесса, то используйте класс ProcessBuilder .
Программные исходники примеров, приведенных в этой статье, доступны на GitHub .
How to pass the user and pwd via the runtime.exec() in java
the problem is wen i run it in java here is my code i think that the line equal to null because something in the set of the password is not correct bat i’m not sure what i’m doing wrong? If its just asking for a password because it needs root, you can add a line in the sudoers file under root to say that your program user is allowed to execute that one specific command as if they were root: https://www.linux.com/blog/configuring-linux-sudoers-file.
How to pass the user and pwd via the runtime.exec() in java
I’m trying to run a simple command using java 1.8 and OS Solaris 11. My program runs under a particular user and the command must run under SuperUser
Runtime.getRuntime().exec(«su — root -c ‘pargs -l 1111′»);
if i run the command in shall its work fine and ask for password and wen i enter the password i will get the result.
the problem is wen i run it in java here is my code
Process proc = Runtime.getRuntime().exec("su - root -c 'pargs -l 1111'"); PrintWriter out = new PrintWriter(new OutputStreamWriter(proc.getOutputStream())); out.println(password); out.flush(); int exitCode= proc.waitFor(); System.out.println(exitCode);//exitCode = 1 BufferedReader pArgs= new BufferedReader( new InputStreamReader(proc.getInputStream())); if((line=pArgs.readLine()) != null) < //do something >else < //something not working = ERROR >
i think that the line equal to null because something in the set of the password is not correct bat i’m not sure
I might suggest a different way around this issue altogether. Instead of trying to run a shell command that dynamically asks for a password, make the command not require a password.
If its just asking for a password because it needs root, you can add a line in the sudoers file under root to say that your program user is allowed to execute that one specific command as if they were root: https://www.linux.com/blog/configuring-linux-sudoers-file.
This would be more secure too as you wouldn’t have the password floating around code.
how to pass the user and pwd via the runtime.exec() in java
You can’t under Solaris if you want to use su .
Solaris su uses the getpass() function to get the necessary password from the user.
From the Solaris getpass() man page:
Description
The getpass() function opens the process’s controlling terminal, writes to that device the null-terminated string prompt , disables echoing, reads a string of characters up to the next newline character or EOF, restores the terminal state and closes the terminal.
.
Errors
The getpass() and getpassphrase() functions may fail if:
.
ENXIO
The process does not have a controlling terminal.
su will either get the password from the controlling terminal, or it will fail.
This is a deliberate design decision to make it almost impossible to perform insecure actions such as automated password entry.
Thank you very much for all the answers. But my solution was a little different. It was decided to use an external file that could be written and read from both processes. The whole goal was to do a handshake again in case the process running at the root will fall (watchdog).
So now there is no need to use the command
Runtime.getRuntime().exec("su - root -c 'pargs -l 1111'");
When the root process starts running, it records a time signature into a file. and if the process of the user (who reads the file every X time) finds that the signature has changed, he will do a handshake again.
Guide to hashCode() in Java, Whenever it is invoked on the same object more than once during an execution of a Java application, hashCode() must consistently return the same value, provided no information used in equals comparisons on the object is modified. This value doesn’t need to stay consistent from one execution of an …
Executing cd and pwd in java program
I have a java program which executes cd unix command as follows:
Process p = Runtime.getRuntime().exec("/bin/sh -c cd test_dir");
Now when I try to do a pwd I’m getting the dir where my java program resides and not the dir which was changed to (should be /root/test_dir)
Process pr = Runtime.getRuntime().exec("pwd");
A child process can’t change the working directory of the parent. You could use ProcessBuilder.directory(File) to set a working directory for the child process. Something like,
ProcessBuilder pb = new ProcessBuilder("pwd"); pb.directory(new File("test_dir")); pb.inheritIO(); pb.start();
How to pass the user and pwd via the runtime.exec() in, My program runs under a particular user and the command must run under SuperUser. here is the command: Runtime.getRuntime ().exec («su — root -c ‘pargs -l 1111′»); if i run the command in shall its work fine and ask for password and wen i enter the password i will get the result. the problem is wen i run it in java here is my code. Usage exampleRuntime.getRuntime().exec(«su — root -c ‘pargs -l 1111′»);Feedback
Change AD Password with Java
I have a good connection to AD. I can authenticate and check error messages from failed auths.
The issue I’m having comes from trying to change the password. I have an LDAPContext established at this point (yes it is an SSL connection). The issue comes from not knowing what value to use in the «username» parameter. I’ve tried all variations I can think of and end up getting one of three errors:
A) NO_OBJECT — I’m assuming this means it is connecting to AD properly but can’t find what I’m looking for.
B) DIR_ERROR — I’m assuming this means it can get into AD properly but doesn’t know wtf I want it to do after that.
C) Some type of ref error that only happens when I don’t qualify the DC, so I think that’s pretty much a given.
Here is the code I am using:
public void changePassword(String username, String password) < ModificationItem[] mods = new ModificationItem[1]; String newQuotedPassword = "\"" + password + "\""; byte[] newUnicodePassword = newQuotedPassword.getBytes(); try < newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE"); >catch (UnsupportedEncodingException e) < e.printStackTrace(); >mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("unicodePwd", newUnicodePassword)); try < ldapContext.modifyAttributes(username, mods); >catch (NamingException e) < System.out.println("Error changing password for '" + username + "': " + e.getMessage()); e.printStackTrace(); >>
Spring has an LDAP module that works very nicely. I’ll bet it will do what you need.
Here is a working example:
package io.fouad.ldap; import javax.naming.AuthenticationException; import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.*; import java.io.UnsupportedEncodingException; import java.util.Hashtable; public class Main < public static void main(String[] args) < final String LDAP_SERVERS = "ldap://AD_SERVER:636 ldap://AD_SERVER2:636"; // separated by single spaces final String LDAP_CONNECT_TIMEOUT_MS = "10000"; // 10 seconds final String LDAP_READ_TIMEOUT_MS = "10000"; // 10 seconds final String AUTHENTICATION_DOMAIN = "domain.com"; final String USERNAME = "username"; final String OLD_PASSWORD = "123"; final String NEW_PASSWORD = "456"; final String TARGET_BASE_DN = "dc=domain,dc=com"; HashtableldapEnv = new Hashtable<>(); ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); ldapEnv.put(Context.PROVIDER_URL, LDAP_SERVERS); ldapEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); ldapEnv.put("java.naming.ldap.version", "3"); ldapEnv.put(Context.SECURITY_PRINCIPAL, USERNAME + "@" + AUTHENTICATION_DOMAIN); ldapEnv.put(Context.SECURITY_CREDENTIALS, OLD_PASSWORD); ldapEnv.put(Context.SECURITY_PROTOCOL, "ssl"); ldapEnv.put("java.naming.ldap.factory.socket", "io.fouad.ldap.MySSLSocketFactory"); //ldapEnv.put("com.sun.jndi.ldap.connect.timeout", LDAP_CONNECT_TIMEOUT_MS); //ldapEnv.put("com.sun.jndi.ldap.read.timeout", LDAP_READ_TIMEOUT_MS); DirContext ldapContext = null; try < ldapContext = new InitialDirContext(ldapEnv); >catch(AuthenticationException e) < System.out.println("Wrong username/password!"); e.printStackTrace(); >catch(NamingException e) < e.printStackTrace(); >if(ldapContext == null) return; SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); NamingEnumeration objects = null; try < objects = ldapContext.search(TARGET_BASE_DN, String.format("(&(objectClass=user)(sAMAccountName=%s))", USERNAME), searchControls); >catch(NamingException e) < e.printStackTrace(); >if(objects == null) return; try < if(objects.hasMore()) < SearchResult entry = (SearchResult) objects.next(); ModificationItem[] mods = new ModificationItem[2]; mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute("unicodePwd", getPasswordByteArray(OLD_PASSWORD))); mods[1] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute("unicodePwd", getPasswordByteArray(NEW_PASSWORD))); ldapContext.modifyAttributes(entry.getName() + "," + TARGET_BASE_DN, mods); System.out.println("Successfully changed the password!"); >else < System.out.println("User (" + USERNAME + ") was not found!"); >> catch(NamingException e) < e.printStackTrace(); >System.out.println("DONE!"); > private static byte[] getPasswordByteArray(String password) < String quotedPassword = "\"" + password + "\""; try < return quotedPassword.getBytes("UTF-16LE"); >catch(UnsupportedEncodingException e) < e.printStackTrace(); return null; >> >
MySSLSocketFactory.java: (Use it at your own risk)
package io.fouad.ldap; import javax.net.SocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.security.SecureRandom; import java.security.cert.X509Certificate; public class MySSLSocketFactory extends SSLSocketFactory < private SSLSocketFactory socketFactory; public MySSLSocketFactory() < try < SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(null, new TrustManager[] @Override public void checkServerTrusted(X509Certificate[] x509Certificates, String s)<> @Override public X509Certificate[] getAcceptedIssuers() < return new X509Certificate[0]; >>>, new SecureRandom()); socketFactory = ctx.getSocketFactory(); > catch(Exception ex) < ex.printStackTrace(System.err); >> public static SocketFactory getDefault() < return new MySSLSocketFactory(); >@Override public String[] getDefaultCipherSuites() < return socketFactory.getDefaultCipherSuites(); >@Override public String[] getSupportedCipherSuites() < return socketFactory.getSupportedCipherSuites(); >@Override public Socket createSocket(Socket socket, String string, int i, boolean bln) throws IOException < return socketFactory.createSocket(socket, string, i, bln); >@Override public Socket createSocket(String string, int i) throws IOException < return socketFactory.createSocket(string, i); >@Override public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException < return socketFactory.createSocket(string, i, ia, i1); >@Override public Socket createSocket(InetAddress ia, int i) throws IOException < return socketFactory.createSocket(ia, i); >@Override public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException < return socketFactory.createSocket(ia, i, ia1, i1); >>
We have a reference for Java fro JNDI here http://ldapwiki.willeke.com/wiki/Set%20Active%20Directory%20Password%20From%20Java
You cannot change the password of a user by just modifying the property that stores it. Instead, you need to use a special LDAP operation SetPassword. I couldn’t find a Java reference, but a C# one, and a Perl one.
Environment variables — What is $PWD? (vs current, The pwd binary, on the other hand, gets the current directory through the getcwd(3) system call which returns the same value as readlink -f /proc/self/cwd. To illustrate, try moving into a directory that is a link to another one: