I'm using ProcessBuilder to execute bash commands:
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try {
Process pb = new ProcessBuilder("gedit").start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
But I want to make something like this:
Process pb = new ProcessBuilder("sudo", "gedit").start();
How to pass superuser password to bash?
("gksudo", "gedit") will not do the trick, because it was deleted since Ubuntu 13.04 and I need to do this with available by default commands.
EDIT
gksudo came back to Ubuntu 13.04 with the last update.
I think you can use this, but I'm a bit hesitant to post it. So I'll just say:
Use this at your own risk, not recommended, don't sue me, etc...
public static void main(String[] args) throws IOException {
String[] cmd = {"/bin/bash","-c","echo password| sudo -S ls"};
Process pb = Runtime.getRuntime().exec(cmd);
String line;
BufferedReader input = new BufferedReader(new InputStreamReader(pb.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
}
input.close();
}
Edit /etc/sudoers with visudo and grant your user a NOPASSWD right for a specific script:
username ALL=(ALL) NOPASSWD: /opt/yourscript.sh
My solution, doesn't exposes the password in the command line, it just feed the password to the output stream of the process. This is a more flexible solution because allows you to request the password to the user when it is needed.
public static boolean runWithPrivileges() {
InputStreamReader input;
OutputStreamWriter output;
try {
//Create the process and start it.
Process pb = new ProcessBuilder(new String[]{"/bin/bash", "-c", "/usr/bin/sudo -S /bin/cat /etc/sudoers 2>&1"}).start();
output = new OutputStreamWriter(pb.getOutputStream());
input = new InputStreamReader(pb.getInputStream());
int bytes, tryies = 0;
char buffer[] = new char[1024];
while ((bytes = input.read(buffer, 0, 1024)) != -1) {
if(bytes == 0)
continue;
//Output the data to console, for debug purposes
String data = String.valueOf(buffer, 0, bytes);
System.out.println(data);
// Check for password request
if (data.contains("[sudo] password")) {
// Here you can request the password to user using JOPtionPane or System.console().readPassword();
// I'm just hard coding the password, but in real it's not good.
char password[] = new char[]{'t','e','s','t'};
output.write(password);
output.write('\n');
output.flush();
// erase password data, to avoid security issues.
Arrays.fill(password, '\0');
tryies++;
}
}
return tryies < 3;
} catch (IOException ex) {
}
return false;
}
Do not try to write a system password plainly in a file, especially for a user that have the sudo privilege, just as #jointEffort answered, issued privilege should be solved by system administrators not by app writers.
sudo allow you to grant privileges for specific command to specific user, which is precisely enough, check this post
and you can choose to manage the privilege in a separated file other than the main sudoers file if you want just append #includedirs /etc/sudoers.d/ in the main /etc/sudoers file(most Linux distributions have already done that) and make a file like ifconfig-user with:
USER_NAME ALL=(ALL) NOPASSWD: /sbin/ifconfig
Another thing, remember to edit the config file with visudo in case you lost control of your system when there is syntax error.
I know this is an old thread but i just want to put this here:
you can use sudo -S *command* as a command that you pass to create the Process instance. Then get the output stream and write the password to it, and add at the end of it a new line and a c. return (\n\r). The return may not be required but i passed it just in case. Also it is a good idea to flush the stream, to make sure everything is written to it. I've done it a few times and it works like a charm. And DO NOT forget to close streams :).
Once you spawn a process you can extract the input and output streams. Just feed the password to the output stream (you output it into the proccess's input). So the code would look something like -
Process pb = new ProcessBuilder("gedit").start();
OutputStream out = pb.getOutputStream();
out.write(password);
Related
I have two strings representing a user and a password for that user. I'd like to check if this is a valid authentication pair in a Unix environment.
I thought about running a sudo bash command to authenticate inside Java code and see if the exit value of the command executed is equal to 0.
However I cannot make this work.
public class Test{
public static void main(String args[]){
String user = "user";
String pass = "pass\n";
try{
Process proc = new ProcessBuilder(
"/bin/sh","-c","sudo","-S","su",user).start();
OutputStream os = proc.getOutputStream();
os.write(pass.getBytes());
os.flush();
os.close();
try{
System.out.println(proc.waitFor());
} catch ( InterruptedException e ){
e.printStackTrace();
}
} catch ( IOException e ){
e.printStackTrace();
}
}
}
This code prints 1 as exit code.
I have really tried everything I could and found on the net but I still have to figure out how to make this work properly.
Can anybody help me?
Thx
sudo asks for the password of the current user, that is, the user that started the java process, so it will not check against user's password.
Instead of "/bin/sh","-c","sudo","-S","su",user).start();try "/bin/sh","-c","su",user).start();. This will just attempt to switch to that user, and as such will ask for user's password.
Based on su.c source code I've wrote a simple java program that makes the user credentials verification using JNA. It must works on all Unix based distributions that have the libc and crypt libraries, bellow a code snippet:
public static void main(String[] args) {
final Scanner scanner = new Scanner(System.in);
System.out.println("type the user");
final String user = scanner.nextLine();
System.out.println("type password");
final String password = scanner.nextLine();
System.out.println("RESULT\n===========================================");
final SPassword passwd = CLibrary.INSTANCE.getspnam(user);
if(passwd == null){
throw new RuntimeException(String.valueOf(Native.getLastError()));
}
final String encrypted = Crypt.INSTANCE.crypt(password, passwd.sp_pwdp);
System.out.printf("matches=%b%n", encrypted.equals(passwd.sp_pwdp));
}
interface Crypt extends Library {
Crypt INSTANCE = Native.loadLibrary("crypt", Crypt.class);
String crypt(String key, String salt);
}
interface CLibrary extends Library {
CLibrary INSTANCE = Native.loadLibrary("c", CLibrary.class);
Password getpwnam(String username);
SPassword getspnam(String username);
}
Testing
git clone https://github.com/mageddo/java-native-examples.git &&\
cd java-native-examples && git checkout -f ef4eb3e &&\
./gradlew clean build fatjar &&\
sudo java -jar build/libs/java-native-examples-all-*.jar
out
type the user
elvis
type password
*********
RESULT
===========================================
matches=true
Obs: The drawback is this application must run as root or sudo user, I can't fix that yet, anyway I think it is possible once su command don't need, for security reasons(if it is a problem in your context) I suggest to isolate this functionality to a application then call it by REST, Soap, TCP, whatever. this way your current application will not need to run as root.
If you want you can replace crypt function by apache commons codec lib function that do the same thing.
Reference
Function to recover user credentials
Lib for encrypt password in Linux format
I want to write a Java code that would perform commands in Windows CMD.
I looked through the site and found out how to send and work with single request. For example create new Process and in execute ("cmd /c dir") then using input stream I can get the answer that is displayed.
How to open the process of cmd and let the user to enter cmd commands?
For example, I open application and it directly opens cmd process, then user can type "dir" and get the output.
After type "cd ../../"
and after type "dir" again and get the output with new path containment.
If it can be performed then how to do it? Or in order to perform this need to open each time a new process and execute ("cmd /c some_reqests")?
Nice question, you can in fact call cmd as a new process and use standard input and standard output to process data.
The tricky part is knowing when the stream from a command has ended.
To do so I used a string echoed right after the command (dir && echo _end_).
In practice I think it would be better to simply start a process for each task.
public class RunCMD {
public static void main(String[] args) {
try {
Process exec = Runtime.getRuntime().exec("cmd");
OutputStream outputStream = exec.getOutputStream();
InputStream inputStream = exec.getInputStream();
PrintStream printStream = new PrintStream(outputStream);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
printStream.println("chcp 65001");
printStream.flush();
printStream.println("dir && echo _end_");
printStream.flush();
for(String line=reader.readLine();line!=null;line=reader.readLine()){
System.out.println(line);
if(line.equals("_end_")){
break;
}
}
printStream.println("exit");
printStream.flush();
for(String line=reader.readLine();line!=null;line=reader.readLine()){
System.out.println(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
try this
Process p = Runtime.getRuntime().exec("ps -ef");
found it at http://alvinalexander.com/java/edu/pj/pj010016
I'm using ProcessBuilder to execute bash commands:
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try {
Process pb = new ProcessBuilder("gedit").start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
But I want to make something like this:
Process pb = new ProcessBuilder("sudo", "gedit").start();
How to pass superuser password to bash?
("gksudo", "gedit") will not do the trick, because it was deleted since Ubuntu 13.04 and I need to do this with available by default commands.
EDIT
gksudo came back to Ubuntu 13.04 with the last update.
I think you can use this, but I'm a bit hesitant to post it. So I'll just say:
Use this at your own risk, not recommended, don't sue me, etc...
public static void main(String[] args) throws IOException {
String[] cmd = {"/bin/bash","-c","echo password| sudo -S ls"};
Process pb = Runtime.getRuntime().exec(cmd);
String line;
BufferedReader input = new BufferedReader(new InputStreamReader(pb.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
}
input.close();
}
Edit /etc/sudoers with visudo and grant your user a NOPASSWD right for a specific script:
username ALL=(ALL) NOPASSWD: /opt/yourscript.sh
My solution, doesn't exposes the password in the command line, it just feed the password to the output stream of the process. This is a more flexible solution because allows you to request the password to the user when it is needed.
public static boolean runWithPrivileges() {
InputStreamReader input;
OutputStreamWriter output;
try {
//Create the process and start it.
Process pb = new ProcessBuilder(new String[]{"/bin/bash", "-c", "/usr/bin/sudo -S /bin/cat /etc/sudoers 2>&1"}).start();
output = new OutputStreamWriter(pb.getOutputStream());
input = new InputStreamReader(pb.getInputStream());
int bytes, tryies = 0;
char buffer[] = new char[1024];
while ((bytes = input.read(buffer, 0, 1024)) != -1) {
if(bytes == 0)
continue;
//Output the data to console, for debug purposes
String data = String.valueOf(buffer, 0, bytes);
System.out.println(data);
// Check for password request
if (data.contains("[sudo] password")) {
// Here you can request the password to user using JOPtionPane or System.console().readPassword();
// I'm just hard coding the password, but in real it's not good.
char password[] = new char[]{'t','e','s','t'};
output.write(password);
output.write('\n');
output.flush();
// erase password data, to avoid security issues.
Arrays.fill(password, '\0');
tryies++;
}
}
return tryies < 3;
} catch (IOException ex) {
}
return false;
}
Do not try to write a system password plainly in a file, especially for a user that have the sudo privilege, just as #jointEffort answered, issued privilege should be solved by system administrators not by app writers.
sudo allow you to grant privileges for specific command to specific user, which is precisely enough, check this post
and you can choose to manage the privilege in a separated file other than the main sudoers file if you want just append #includedirs /etc/sudoers.d/ in the main /etc/sudoers file(most Linux distributions have already done that) and make a file like ifconfig-user with:
USER_NAME ALL=(ALL) NOPASSWD: /sbin/ifconfig
Another thing, remember to edit the config file with visudo in case you lost control of your system when there is syntax error.
I know this is an old thread but i just want to put this here:
you can use sudo -S *command* as a command that you pass to create the Process instance. Then get the output stream and write the password to it, and add at the end of it a new line and a c. return (\n\r). The return may not be required but i passed it just in case. Also it is a good idea to flush the stream, to make sure everything is written to it. I've done it a few times and it works like a charm. And DO NOT forget to close streams :).
Once you spawn a process you can extract the input and output streams. Just feed the password to the output stream (you output it into the proccess's input). So the code would look something like -
Process pb = new ProcessBuilder("gedit").start();
OutputStream out = pb.getOutputStream();
out.write(password);
I am creating a wrapper for a executable that runs on the windows command line. The executable takes a few commands then attempts to connect to another device. then it outputs and ERROR! or Ready For "Device Name" i do not get this message until the app exits. The problem is this app is a tunnel allowing me to run telnet on the external box but i need to make sure the Device is ready this is my code.
public void startUDPTunnel() {
//TODO Pull Amino serial number from webportal
Properties prop = new Properties();
InputStream inConfig = getClass().getClassLoader().getResourceAsStream("config.properties");
try {
prop.load(inConfig);
} catch (IOException e) {
System.out.println(e.getMessage());
}
String server = prop.getProperty("server");//config.GetProp("server");
System.out.println(server);
String port = prop.getProperty("port");//config.GetProp("port");
System.out.println(port);
String location = prop.getProperty("location");//config.GetProp("location");
System.out.println(location);
String url = prop.getProperty("URL");
System.out.println(url);
String input = "";
try {
input = getSerial(url);
System.out.println(input);
Process p = Runtime.getRuntime().exec(location+"udptunnel.exe -c 127.0.0.1 23 "+input+" "+server+" "+port+" 127.0.0.1 23");
threadSleep();
BufferedReader in = new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
if(line.equals("ERROR!")){
System.out.println("There was an ERROR");
}
if(line.equals("Ready for \""+input+"\"")){
System.out.println("Load Telnet");
}
}
p.destroy();
} catch (IOException e) {
e.printStackTrace();
}
}
Sorry there is a lot of debug code left in this function.
EDIT
OK I am pretty sure know what the issue is bufferReader.readLine() requires a \n or \r or just hangs is there anyway to watch the stream with out the buffer?
You should use a ProcessBuilder, and then use redirectErrorStream(). I think this will cause stdout of the process to be unbuffered. And even if it doesn't, you'll only have to read from one InputStream to get both stdout and stderr.
I have figured out my problem the applications that i am executing with java do not have a EOL at the end of the line in fact they just hang on the line For example telnet waits for the username then the password. i am not sure this is proper but it works and is what i am going to use for now
while((i=br.read())!=-1){
ch += (char)i;
}
This outputs every char as they come in when then i just make sure the string contains what i am looking for!
I'm trying to find a solution how to implement a multiple command - response interaction with the Windows cmd shell. Example:
Start the cmd shell
"dir"
wait for and Handle input
Execute new command depending on the input content
wait for and Handle input
etc.
PLEASE NOTE! Steps above were only to describe the way of communication, it is NOT my intention to browse the file system, i.e. the actual commands could be something else.
Approach so far:
try {
Runtime rt = Runtime.getRuntime();
p = rt.exec("cmd");
error = p.getErrorStream();
input = p.getInputStream();
output = new PrintStream(p.getOutputStream());
StreamGobbler errGobbler = new StreamGobbler(error, "ERROR");
StreamGobbler inGobbler = new StreamGobbler(input, "INPUT");
errGobbler.start();
inGobbler.start();
output.println("dir");
output.flush();
sleep(5);
output.println("dir");
output.flush();
} catch (IOException e) {
System.out.println(e.printStackTrace());
}
StreamGobbler class:
class StreamGobbler extends Thread
{
InputStream is;
String type;
ArrayList<String> cmdRespArr = new ArrayList<String>();
StreamGobbler(InputStream is, String type) {
this.is = is;
this.type = type;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader bf = new BufferedReader(isr);
String line = null;
while ( ( line = bf.readLine() ) != null ) {
cmdRespArr.add(line);
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
In this example however the while loop in the run method never returns between the issued commands (this is not part of the problem).
So, would the approach be to let the while method add the line read to a collection or other container, and then monitor that one for something indicating that the cmd shell is ready for input (which would in turn indicate that all available input from previous command have been read). And then fire off the next command?
In the example above this indication would get rid off the sleep call which right now is only there for debugging purposes.
I have a vague memory that this was the approach when doing it with Python.
Or is this totally wrong?
Will it be a solution to start multiple command processors, i.e. one per command?
I'm asking because with keeping one command processor open, it is very hard to determine when a command has been processed, unless you parse the output line by line and wait until you see the prompt in the output.
With multiple processors, i.e. executing "cmd /c dir" then input output redirs will close when the command has completed (and the associated process terminated).
Of course this will not work, if some commands depend on others, e.g. doing a chdir and expecting the next command to work in that dir.