I have a Java program running on linux that needs to be able to both set a users initial samba password, and then allow them to change their password without giving them access to the terminal.
Below is my code for changing the users password, as this is easier to test with, and I will be able to figure the other part out once I get this worked out.
The -s flag is supposed to allow stdin to be used.
String cmd = "smbpasswd -s -U user";
Process p = Runtime.getRuntime().exec(cmd);
OutputStreamWriter Out = new OutputStreamWriter(p.getOutputStream());
InputStreamReader In = new InputStreamReader(p.getInputStream());
BufferedWriter Write = new BufferedWriter(Out);
BufferedReader Read = new BufferedReader(In);
char[] output = null;
//I write all of the output lines to the log, but nothing is written, and the password doesn't change.
Read.read(output);
Write.write(OldPass);
Read.read(Output);
Write.write(NewPass);
Read.read(Output);
Write.write(NewPass);
Read.read(Output);
I need some help to figure out what I am doing wrong, and how I would go about this correctly. Any help is appreciated.
According to the man page for SMBPASSWD(8):
-s: This option causes smbpasswd to be silent (i.e. not issue prompts) and to read its old and new passwords from standard input, rather than
from /dev/tty (like the passwd(1) program does). This option is to aid
people writing scripts to drive smbpasswd
Emphasis on "not issue prompts". If I'm reading your code correctly, you seem to be waiting for prompts from the utility, which won't come (test it from the command line). But I may have misinterpreted your Java code.
Related
I know that one can take a screenshot from the Android device via ADB with
$ adb shell screencap -p /mnt/sdcard/sc.png
$ adb pull /mnt/sdcard/sc.png
However this writes a file on your phone and on your PC, which I want to avoid.
So I found the following SO question and the answer suggested that the image gets printed to the Std output when you do not specify a file.
I tested this from console and it really printed binary data to the console.
Android: It there a way to read screenshot from memory without saving to internal/external storage?
Now I want to utilize this technique and start a process from java, execute the
adb shell screencap
command, read the output and create a BufferedImage from the output.
I tried something like this
ProcessBuilder pb = new ProcessBuilder("cmd");
Process start = pb.start();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
bw.write("adb shell screencap");
bw.newLine();
bw.flush();
// wait some time for the process to print the image to the console
start.waitFor(10, TimeUnit.SECONDS);
StringBuilder sb = new StringBuilder(9000000);
Scanner s = new Scanner(start.getInputStream());
while (s.hasNext()) {
sb.append(s.next());
}
String result = sb.toString();
Unluckily there are quite a few issues with my Code.
the program does not terminate after getting the screenshot - so start.waitFor does not quite work as I wanted it to work
currently my code reads characters, where i actually want to read bytes
reading with scanner seems kind of slow when reading millions of characters/bytes
Maybe someone can point me in a direction such that I can get it to work.
Thanks!
Why complicating things. If you are invoking adb and want its output just run
adb exec-out screencap -p > myimg.png
exec-out is used instead of shell to get raw data (i.e. the image).
After searching some more time I came across ddmlib which already has the functionality to take screenshots and perform various other tasks via ADB built in.
The library works great and definitely made it easier for me to execute commands via ADB.
This question already has answers here:
Bitlocker script to unlock drive
(8 answers)
Closed 6 years ago.
I am trying to unlock a drive secured by bitlocker from Java. As far as I know there are no libs which can help me to handle that, so I was trying it through cmd. Here's the code:
public static boolean unlockDisk(String pwd) throws IOException
{
String[] script =
{
"manage-bde.exe", "-unlock", "D:", "-password",
};
Process process = new ProcessBuilder(script).start();
InputStream inputStream = process.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
final OutputStream outputStream = process.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
writer.write(pwd);
writer.newLine();
writer.close();
System.out.println("--------------------------------------");
System.out.println("Bitlocker log:");
String line;
while ((line = bufferedReader.readLine()) != null)
{
System.out.println(line);
}
bufferedReader.close();
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
System.out.println("Here is the standard error of the command (if any):\n");
String tmp;
while ((tmp = stdError.readLine()) != null)
{
System.out.println(tmp);
}
System.out.println("--------------------------------------");
return true;
}
My Problem
If I execute this java code I get The handle is invalid with Code 0x80070006.
What I already tried
Different JDK Version 32 and 64 Bit Java 8 and Java 7 (JDK 32 complains somehow that it can't find the command manage-bde)
Different combinations of output streams, with and without newline...
Another script command for the processbuilder like "cmd.exe", "/k", "manage-bde.exe", "-unlock", "D:", "-password", or with /c instead of /k
With and without admin rights
Simple *.bat with the command manage-bde.exe -unlock D: -password (which works perfectly)
Locking the drive through a java command (which works perfectly)
The command without -password (which let's bitlocker claim that I have to define how I want to unlock the drive)
I googled around for some time and found others having this problems but in a different way with other applications. So it seems like a very common error message.
My guess
I think it has something to do with how I handle my Java output as Bitlocker input. Maybe I am using the wrong streams to write to.
I can't provide the value of the password within the script variable, because Bitlocker want doesn't accept that way of entering the password. Usually you enter manage-bde -unlock D: -password within the command line and after a few lines of output Bitlocker asks you for the password.
Well I described it as good as I can and hope that someone knows what the problem is.
Any suggestion, even if it just leads to a more precise error message, would be appreciated. If you have any questions, just let me know!
Thanks in advance!
I encountered same problem recently. I did a lot search. It seems that mange-bde.exe doesn't read user input from stdin. Someone said ssh client and telent clent running on Linux doesn't read password from stdin. Another example Linux command passwd. It has a flag called -stdin which enable the shell to read password from stdin. Therefore, I guessed manage-bde.exe may works in a similar way.
My solution is simulating keyboard input. The awt package can do the job.
I have rsync command to be run in a java program...the problem i am facing is that rsync requires a password to be entered and i am not understanding how to pass this password to the rsync command to work?
I was gonna post this code sample:
Process rsyncProc = Runtime.exec ("rsync");
OutputStreanm rsyncStdIn = rsyncProv.getOutputStream ();
rsyncStdIn.write ("password".getBytes ());
But Vineet Reynolds was ahead of me.
As Vineet Reynolds pointed out using such approach will require an additional piece of code to detect when rsync requires a password. So using an external password file seems to be an easier way.
P.S.: There may be a problem related to the encoding, it can by solved by converting the string to a byte array using appropriate encoding as described here.
P.P.S.: It seems that I can't yet comment an answer, so I had to post a new one.
Took me some time, but here it goes:
Process ssh = Runtime.getRuntime ().exec (new String[] {"rsync", ... /*other arguments*/});
Reader stdOut = new InputStreamReader (ssh.getInputStream (), "US-ASCII");
OutputStream stdIn = ssh.getOutputStream ();
char[] passRequest = new char[128];//Choose it big enough for rsync password request and all that goes before it
int len = 0;
while (true)
{
len += stdOut.read (passRequest, len, passRequest.length - len);
if (new String (passRequest, 0, len).contains ("password:")) break;
}
System.out.println ("Password requested");
stdIn.write ("your_password\n".getBytes ("US-ASCII"));
stdIn.flush ();
P.S.: I don't really know how rsync works, so you may need to change it a bit - just run rsync manually from a terminal an see how exactly it requests a password.
You can write to the output stream of the Process, to pass in any inputs. However, this will require you to have knowledge of rsync's behavior, for you must write the password to the outputstream only when the password prompt is detected (by reading the input stream of the Process).
You may however, create a non-world readable password file, and pass the location of this password file using the --password-file option when you launch the rsync process from Java.
Need not wait till the password is requested to write it to the stream. Make use of a BufferedWriter instead.
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(process.getOutputStream())
);
writer.write(passwd, 0, passwd.length());
writer.newLine();
writer.close();
This must work.
I'm trying to launch an external program from my java swing app using this:
Process proc = Runtime.getRuntime().exec(cmd);
But the external program never actually gets launched until I close out of my java app...everytime.
It waits to launch only after I have closed out.
the external program I am trying to run is an exe that takes arguments so:
cmd = "externalProgram.exe -v --fullscreen --nowing";
What could possibly be wrong here.
Funny enough it works as expected if i try something simple like:
Process proc = Runtime.getRuntime().exec("notepad.exe");
You may need to read from the process's standard output, or close the standard input, before it will proceed. For reading the output, the problem is that the buffer can get full, blocking the program; for closing the input, the problem is that some programs will try to read data from there if it's available, waiting to do so. One or both of these tricks is very likely to straighten things out for you.
You may also read the error output stream to check it the program is actually being unsuccessfully executed
String cmd = "svn.exe";
Process proc = Runtime.getRuntime().exec(cmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String line = null;
while((line=reader.readLine())!=null){
System.out.println(line);
}
reader.close();
My console shows
Type 'svn help' for usage.
Which evidently shows the program was executed by Java.
I am using Java on Windows XP and want to be able to send commands to another program such as telnet.
I do not want to simply execute another program. I want to execute it, and then send it a sequence of commands once it's running.
Here's my code of what I want to do, but it does not work:
(If you uncomment and change the command to "cmd" it works as expected. Please help.)
This is a simplified example. In production there will be many more commands sent, so please don't suggest calling "telnet localhost".
try
{
Runtime rt = Runtime.getRuntime();
String command = "telnet";
//command = "cmd";
Process pr = rt.exec(command);
BufferedReader processOutput = new BufferedReader(new InputStreamReader(pr.getInputStream()));
BufferedWriter processInput = new BufferedWriter(new OutputStreamWriter(pr.getOutputStream()));
String commandToSend = "open localhost\n";
//commandToSend = "dir\n" + "exit\n";
processInput.write(commandToSend);
processInput.flush();
int lineCounter = 0;
while(true)
{
String line = processOutput.readLine();
if(line == null) break;
System.out.println(++lineCounter + ": " + line);
}
processInput.close();
processOutput.close();
pr.waitFor();
}
catch(Exception x)
{
x.printStackTrace();
}
That looks OK, as it won't be producing that much output, but you should really read and write in separate threads so it doesn't fill up the buffer and block waiting you to read before you reach the next step.
So if it's reaching the point where you flush the command you send to it, find out whether the Windows telnet client supports receiving commands from standard input rather than a console by piping the text you're sending to its standard input to it in a command prompt.
For example, echo dir c:\ | cmd causes cmd to run, list the c: drive contents and exit, much the same behaviour as if you typed dir c:\ into the console. But echo open localhost | telnet causes telnet to clear the screen then exit, rather than behaving the same way as if you typed it into the console. As telnet needs to mask user input for passwords, it's quite likely that it's using the console API rather than reading from standard input. It's help doesn't list any command arguments to tell it to read from standard input, so maybe you need to use a telnet implementation which is better suited to scripting.
It's not directly an answer to your question, but...
Instead of using Runtime.exec() you should use a ProcessBuilder and redirect stderr to stdout (ProcessBuilder.redirectErrorStream(true)). Otherwise your process could block if it writes something to stderr (Windows doesn't like it when the output of a process isn't read).
If you want to control a telnet session programatically from Java, you might be able to use this Java telnet library... you can do the same things (open connections, send username/password, send commands and receive results) but without actually spawning a separate process.
You may take a look at the Telnet Ant task you can call it directly in your code with out having to use a build.xml file.
You can also take a look at the source code and see how they do it.