How to run sudo command for OS X in java - java

I am working on app in javafx , I am trying open an application using a command in terminal, I am running the command using my java code my command have some variable it's have path of my installer file which will not always be same because file name can be different as the builds are updated.
here is a sample as how I am running the command it's not the exact command which I am running but the command format is same.
Process process = Runtime.getRuntime().exec("echo password | sudo -S open -a safari");
String line;
BufferedReader input = new BufferedReader(new InputStreamReader(pb.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
}
input.close();
The process is not giving any output it stops there and nothing happens.
The same command I have tried from terminal and it works fine.
I have tried the things mention in this link
How to execute bash command with sudo privileges in Java?
but it also didn't worked.
I am also running command like "chmod +x" from my java code these commands runs fine.
my original command looks like this:-
runCommand = "echo" + " " + password + "| sudo -S " + "\"" + a.getAbsolutePath() + "\"" + " --deploymentFile="
+ "\"" + b.getAbsolutePath() + "\"";
where a.getAbsolutePath() is the path of the installer file and b.getAbsolutePath() is the path of the deployment file we used to install the application.
pb.getInputStream()
prints the command and when I copy and paste it is terminal it's runs fine.
pb.getErrorStream()
doesn't give anything.
I have tried running
String[] cmd = {"/bin/bash","-c","echo tester| sudo -S ","\"",a.getAbsolutePath(),"\"","\""," --deploymentFile=","\"",b.getAbsolutePath()};
and
String[] cmd = {"/bin/bash","-c","echo tester| sudo -S",a.getAbsolutePath(),"--deploymentFile=","\"",b.getAbsolutePath()};
also
here I got following error
getErrorStreamusage: sudo -h | -K | -k | -L | -V
getErrorStreamusage: sudo -v [-AknS] [-g groupname|#gid] [-p prompt] [-u user name|#uid]
getErrorStreamusage: sudo -l[l] [-AknS] [-g groupname|#gid] [-p prompt] [-U user name] [-u
getErrorStream user name|#uid] [-g groupname|#gid] [command]
getErrorStreamusage: sudo [-AbEHknPS] [-C fd] [-g groupname|#gid] [-p prompt] [-u user
getErrorStream name|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] [<command>]
getErrorStreamusage: sudo -e [-AknS] [-C fd] [-g groupname|#gid] [-p prompt] [-u user
getErrorStream name|#uid] file ...

sudo
I'd strongly suggest to edit the sudoers file and allow the user running the application to use the specific commands via sudo without prompting for a password instead of doing an echo passwd | sudo ... construction.
That way you avoid storing passwords in the clear (or at best slightly obfuscated) in an application or configuration file, and you avoid the need to call a shell with a shell script that calls sudo, etc.
Sudoers can be edited via the command visudo. See here as an example how it is done on unbuntu, but it's the same on any unix. https://askubuntu.com/questions/159007/how-do-i-run-specific-sudo-commands-without-a-password
Additional ref: https://www.sudo.ws/man/1.8.16/sudoers.man.html
I think you're asking the wrong question though...
Authorization on a mac
On a mac applications that need to perform operations that require additional rights are not supposed to use sudo to start with.
An app is supposed to use the authorization services instead.
References:
Introduction to Authorization Services Programming Guide (apple)
Authorization Services Tasks (apple)
I need to give a java application super user access to view protected files on a mac
Is there any graphical "sudo" for Mac OS X?

I think you must use the full path to the application. This should work:
Runtime rt = Runtime.getRuntime();
rt.exec("echo password | sudo -S open -a /Applications/Safari.app");
Update:
Based on your comment you could try to split the process. The chances are good that open needs an interactive session.
Create a script (e.g. openSafari.sh) that will open Safari as user.
#!/etc/bash
echo $1 | sudo -S open -a /Applications/Safari.app &
Make it executable: chmod +x openSafari.sh, and call that script from java.
Runtime rt = Runtime.getRuntime();
rt.exec("/pathTo/openSafari.sh 'sudoPassword'");

I would NOT recommend doing this - do not shout at me if you break something :)
But what you are asking for can be achieve with:
String[] cmd = {"/bin/bash","-c","echo password | sudo -S open -a <path to app>"};
Process pb = Runtime.getRuntime().exec(cmd);

The Runtime.exec() methods run the given command directly, not via a shell. The particular overload you are using tokenizes the command at whitespace, and interprets the resulting tokens as the name of the command and the arguments. The only command executed by your invocation ...
Runtime.getRuntime().exec("echo password | sudo -S open -a safari");
... is therefore echo; everything else is an argument. The result is the following output to the process's standard output:
password | sudo -S open -a safari
There are at least a couple of ways to accomplish what you appear to want. The simplest modification of your original code would probably be
Process process = Runtime.getRuntime().exec(
new String[] { "bash", "-c", "echo password | sudo -S open -a safari" });
That achieves what you thought you were getting, by explicitly invoking a shell to run the command.
But that's a substantial security risk, because the password will appear in plain text in the process list. You can instead have your Java program feed in the password directly, and then also avoid getting bash involved:
Process process = Runtime.getRuntime().exec("/usr/bin/sudo -S open -a safari");
Writer toSudo = new OutputStreamWriter(process.getOutputStream());
String password = "password";
toSudo.write(password);
toSudo.write('\n'); // sudo's docs demand a newline after the password
toSudo.close(); // but closing the stream might be sufficient
Other considerations:
It is wise to give a full path to the sudo command, as demonstrated, to avoid running a different sudo that happens to be found first in the path. Since you're going to give it the password to a privileged account, it is important to minimize the possibility of running a rogue program.
It would also be wise to avoid storing passwords in the program or in a configuration file; thus, solutions that involve feeding a password to sudo should also involve inputting the password interactively from a user.
Security-conscious Java programs often prefer to keep passwords in char arrays instead of in Strings, so that they can be proactively wiped when no longer needed. Strings cannot be changed, and they may hang around inside the VM indefinitely (even more so than many other objects).
Generally speaking, you need to drain a Process's input and error streams, concurrently, whether you do anything with the contents or not. If you do not do so then the external process may block and / or may fail to exit. That's probably not an issue with safari in particular, however, because I don't think it ordinarily produces any output on those streams.

maybe use this
How to setup a SUDO_ASKPASS environment variable?
You can set the SUDO_PROMPT enviroment variable within the process call
Combine that with the fix to how you're using process jon bollinger, maciej, etc have mentioned.
Then have that bring up a password prompt for your user, or access a pki with your credentials in it. (for the love of god at least aes encrypt it if you go for the pki)
as you've said this is meant to run on others machines, it'll basically be a shitty uac prompt and that doesn't sound like a very mac/linux solution. swa66 is the best way, but this'll do quick and dirty.

Related

Running pmcmd from java

I am trying to run pmcmd and pass arguments from java. This is my code :
String cmd="C:\\Informatica\\9.6.1\\clients\\PowerCenterClient\\CommandLineUtilities\\PC\\server\\bin\\pmcmd.exe";
final Process cmdProcess;
cmdProcess = Runtime.getRuntime().exec(new String[]{cmd,"connect -sv IS_NAME -d DOMAIN_NAME -u USER -p PWD"});
cmdProcess.getOutputStream().close();
The problem is I am not able to get the desired output. I get the following error:
ERROR: Unknown command [connect]
When I try the same command on the command line, it works.
pmcmd>connect -sv IS_NAME -d DOMAIN_NAME -u USER -p PWD
The output:
Connected to Integration Service:[IS_NAME].
Can anyone tell what mistake I am doing?
(adding my comment as an answer, after it worked according to the OP)
Your command line example suggests that the connect -sv ... is issued within the pmcmd process, and not provided as an argument.
So you should probably send that to the process' STDIN (accessed by cmdProcess.getOutputStream()) instead of passing as argument to the call.
pmcmd works in two modes, command line and interactive. connect command works in interactive mode only.
When invoking from java, you are using command line mode, and do not need to connect first. You can directly invoke the command you intend to run (ex. startWorkflow) and provide the connection parameters with that command like below:
pmcmd startworkflow -sv MyIntService -d MyDomain -u seller3 -p jackson ‑f SalesEast wf_SalesAvg
More details here.
I had to issue a command within the pmcmd process. So I modified my code and it works :
String cmd="C:\\Informatica\\9.6.1\\clients\\PowerCenterClient\\CommandLineUtilities\\PC\\server\\bin\\pmcmd.exe";
final Process cmdProcess;
cmdProcess = Runtime.getRuntime().exec(new String[]{cmd,""});
OutputStream out = cmdProcess.getOutputStream();
out.write("connect -sv IS_NAME -d DOMAIN_NAME -u USER -p PWD".getBytes());
out.close;

Run sudo command using Java processBuilder

I need to run a sudo command from within java, and redirect the output to a file, using processbuilder or similar.
Two questions:
Will piping the sudo password using echo work as follows?
Although the file gets created, nothing is ever written to it. Any ideas why?
ProcessBuilder conntrack_process = new ProcessBuilder("/bin/bash", "-c", "echo '<passwordhere>' | sudo conntrack -L");
conntrack_process.redirectOutput(new java.io.File("/home/<homedir>/conntrack_out.txt"));
Process ct_process = conntrack_process.start();
ct_process.waitFor();
ct_process.destroy();
I am using Ubuntu 16.04.
Old question but instead of trying to echo password you should setup your sudoers file to allow just that command with no password for that user
myusername ALL = (root) NOPASSWD: /path/to/my/program
https://unix.stackexchange.com/questions/18830/how-to-run-a-specific-program-as-root-without-a-password-prompt
First, you need to use -S with sudo to make it read the password from its stdin.
Second, you should read or redirect the error stream somewhere to be aware of any errors.

HOME environment variable not set in bash script

I have a Java program that spawns a bash script that calls another script. In that second script, I'm finding that the $HOME variable is not set. Here's the gist of it:
In Java:
Process p = new ProcessBuilder("bash", "-l", "/foo/a.sh").start();
// code to actually execute p
/foo/a.sh:
#!/bin/bash
/foo/b.sh
/foo/b.sh:
#!/bin/bash
echo "HOME=$HOME"
This echoes "HOME=". The eventual problem is that $HOME/bin is supposed to be added to my PATH in ~/.profile, but since that's not happening, a bunch of custom executables aren't being made accessible.
I worked around it by doing:
if [ -d ~/bin ] ; then
PATH=~/bin:"$PATH"
fi
And that works fine. But I guess I just want to understand why $HOME wasn't being set. It seems like $HOME and ~ should be largely equivalent, no? There's probably something I'm fundamentally missing about how this environment is getting set up.
I am running Ubuntu 12.04.5, if that makes a difference.
The evidence suggests that HOME is missing from the environment in which the Java app is running. Assuming that the app doesn't explicit unset HOME, the most likely reason is that the app is being started from some context other than a login by the user the app is running as.
It's correct that ~ and $HOME are similar. If HOME is present in the environment, even if it is set to the empty string, ~ will be replaced with $HOME. However, if HOME is not present in the environment, bash will attempt to find the home directory for the currently logged in user, and use that for ~.
eg.
$ bash -c 'echo ~'
/home/rici
$ HOME='Hello, world!' bash -c 'echo ~'
Hello, world!
$ HOME= bash -c 'echo ~'
$ (unset HOME; bash -c 'echo ~';)
/home/rici
Since your workaround requires the equivalent of the last scenario, I conclude that HOME has not been set, or has been unset.

Android: Passing outputstream of top command to the inputstream of grep to achieve piping " | "similar in shells

I'm essentially trying to accomplish the same result that running the command:
"top -n 1 -s cpu | grep -E 'list_of_package_names'"
on a machine that supports shell features such as piping ( | ) would return. That being the rows that are returned by the top command that contain the package name filtered by grep. Normally pretty simple stuff with shell features, however to my knowlegde android does not come with a commands shell and access to these command can only be achieved using Runtime:
Process p = Runtime.getRuntime().exec(...);
and then getting the inputstream and reading from it.
The problem is that Runtime.getRuntime().exec(...); does not know how to deal with shell language and the piping of commands. So is there a way to pipe the ouput of the the top command to the input of the grep command to essentially create the same functionality? Or is there a way to run the commands from a script or anything else that can achieve this result?
On a side note, I have been using adb client/server protocol in my shell commands to test the correctness of the syntax for example:
Runtime.getRuntime().exec("adb shell top -n 1 -s cpu | grep -E '" + shellParams + "'");
This returns the expected result as the adb shell contains shell features however cannot be used outside of debugging i.e. at runtime.
Any help would be greatly appreciated, this is my first post so please do let me know if I should be structuring my answer at all differently.

Not able to run grep command

I was trying to run the following instruction,
Process p = Runtime.getRuntime().exec("/system/bin/lsof|grep mediaserver");
In android(java) but I am getting error. if I run following instruction,
Process p = Runtime.getRuntime().exec("/system/bin/lsof ");
the file is successfully saved.Can anyone tell what is the error? Actually I want to list and check if media server service is being running or not.
The grep utility may not be installed on your device.
You can check it by trying the following in a console:
> adb shell
$ grep
grep: not found
The last line indicates that this command is not available.
The problem is that Runtime.getRuntime().exec(...) does not know how to deal with the shell language. On a Linux / Unix platform you would so something like this:
Process p = Runtime.getRuntime().exec(new String[]{
"/bin/sh", "-c", "/system/bin/lsof | grep mediaserver"});
However, (apparently) Android doesn't have a command shell / command prompt by default. So either you need to identify and install a suitable shell on your device, or construct the pipeline "by hand"; i.e. by creating a "pipe" file descriptor, and execing the two commands so that lsof writes to the pipe and grep reads from it.
Maybe the answer is to run it like this ...
Process p = Runtime.getRuntime().exec(
"adb shell /system/bin/lsof | grep mediaserver");
(Try running the "shell ...." part from adb interactively before doing it from Java.)

Categories