How to run superuser commands on Linux through Java code? - java

My application has multiple users and 1 superuser. I am trying to write and store a file in Linux through Java code but i get permission denied error. I used the following code:
Process process = Runtime.getRuntime().exec("/usr/bin/tiff2pdf -o /tmp/tiff_dir/temp.pdf /tmp/tiff_dir/image.tiff");
int returnCode = process.waitFor();
I get following error:
java.io.FileNotFoundException: image.tiff (Permission denied)
From my analysis, it seems that because the user does not have root permissions, i am getting this error. What is the solution to this?

You shouldn't run a command like that as a super user because it poses a security risk (i.e. if someone gained control of your java program, then they have the keys to the kingdom). Instead, you should run with lower permissions.
It looks like the issue is with access to image.tiff not with tiff2pdf. Check the owner and permissions of image.tiff.

Firstly, these two lines will not produce a java.io.FileNotFoundException: image.tiff (Permission denied):
Process process = Runtime.getRuntime().exec("/usr/bin/tiff2pdf -o temp.pdf image.tiff");
int returnCode = process.waitFor();
If for some reason, the command fail, it will return a non-zero return code will produce some output on the process's standard error (that's the convention). You can get that standard error from process.getErrorStream() (it might be worth having a look at the standard output too, just in case). If there's an issue with the file not being found there, it will not throw a FileNotFoundException like this, since Java cannot understand the expected output from your command.
EDIT, following your comment:
It was thrown from this point only and value of returnCode was 1. Also everything worked fine once i manually changed the file permissions from a root user.
That's just not possible. If your application throws an exception at either of these two lines, it will exit the normal control flow: you will not be able to read the returnCode at all.
Secondly, your should run your exec command with each argument in a String[] instead of having it all in one line, this should prevent quotation problems if file names have spaces for example.
I would also suggest using absolute paths in your command, to make sure you're working in the directories you expect. (*EDIT: * Now that you're using absolute paths, make sure your user has rwx permissions on /tmp/tiff_dir .)
To answer your question more directly, you can certainly run sudo with Runtime.exec(new String[] {"/usr/bin/sudo", ... the rest of your command ... }, but this is a bad idea, for security reasons. You'd also need to change the sudoers file to allow it without password, or find a way to pass in a password, either on the command line (definitely a security risk!) or by passing it to the input stream manually, somehow.)

Try this :
File file = new File("/opt/image.tiff");
Runtime runtime = Runtime.getRuntime();
runtime.exec(new String[] { "/bin/chmod", "777",file.getPath()});
This will execute full permission on the file.

Related

Set file permission using octal notation in java

I want to create files and directories from my java code with required unix permissions. The unix permissions are taken as input from user and are given as octal number(For e.g. 02775). I found the java.nio.file.attribute.PosixFilePermission to be quite handy however it doesn't allow setting the setgid (+s) bit. Following code throws java.lang.IllegalArgumentException: Invalid mode
Set<PosixFilePermission> posixPermissions = PosixFilePermissions.fromString("rwxrwsr-x");
Files.setPosixFilePermissions(someDir, posixPermissions);
Also I want to avoid manually converting the octal number to posix permission string(e.g: "rwxrw-r-x"). Is there any way to do this in java apart from triggering a sub-process with chmod command ?

-usedefaultlisteners treated as file when supplied as command line argument to testNG

Sorry if this question has already been answered some where, I have not had any luck turning up a solution. This is my first SO post, if information is missing/unclear, or the formatting sucks, let me know, I will update the post.
I am using TestNG version 6.13.1 (also tested with 7.0.0-beta1). I am running this command (not the full command, the class path is massive, and there are multiple -D options)
java -cp <classpath stuff...> -DappiumPort=30000 org.testng.TestNG -usedefaultlisteners false /Users/.../adbservice/test-results/3567/test_config/Test_Suite_testT13googleMaps.xml
expecting that testNG will recognize the first argument as a switch, and turn the default listeners off. This is based on reading Turning off test-output in TestNG and http://testng.org/doc/documentation-main.html#testng-xml, and other less relevant documents.
What actually happens is testNG appears to treat all the arguments as if they are file paths, and I get a very helpful error message
ProcessResults(exitCode=0, output=java.io.FileNotFoundException: /Users/.../adbservice/-usedefaultlisteners false testng.xml (No such file or directory)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:196)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:139)
at org.testng.xml.Parser.parse(Parser.java:148)
at org.testng.xml.Parser.parse(Parser.java:233)
at org.testng.TestNG.parseSuite(TestNG.java:290)
at org.testng.TestNG.initializeSuitesAndJarFile(TestNG.java:334)
at org.testng.TestNG.initializeEverything(TestNG.java:974)
at org.testng.TestNG.run(TestNG.java:988)
at org.testng.TestNG.privateMain(TestNG.java:1330)
at org.testng.TestNG.main(TestNG.java:1299)
The command itself is issued from Java, using a wrapper around a ProcessExecutor. The code looks like
new ProcessExecutor()
.command(cmd)
.readOutput(true)
.timeout(waitForTimeMs, TimeUnit.MILLISECONDS)
.execute();
I can get the same error if I capture the command input and paste it into the shell, so it seems that it is not a problem with the java code itself, but I figured I would include that information for completeness.
My question is, how can I make this call to testNG work using the command line arguments? There seem to be few alternatives because I have packaged tests which are executed in a shell process.
Edit
Since this is such a common case, I am convinced there is something wrong on my side. I tested that theory out by creating a really simple java project with a smoke test, and then ran it with
java -cp .:testng-6.13.1.jar:jcommander-1.72.jar:build/libs/test-1.0-SNAPSHOT.jar org.testng.TestNG -usedefaultlisteners false testng.xml
which worked exactly as described in the documentation. Therefore I think there is something going on with the input to java and how it is being processed that is causing the error with testNG.
Edit 2
Did some further investigation on my side, eventually I tried the original generated java command with the parameters ( -usedefaultlisteners false) on the command line, and lo and behold it worked, or at least, it did some stuff before bombing out, instead of complaining about the parameters being invalid file paths, which was my original result when running on the command line. Maybe I had the wrong directory or some such the first time, but this suggests that it is a problem with handling the command with this ProcessExecutor.
Edit 3
Paydirt. It turns out the ProcessExecutor library does not handle command line input with spaces as one might expect, so for example,
Lists.newArrayList(
"java", "-cp", ".:", "org.testng.TestNG", "-enabledefaultlisteners false", "testng.xml"
)
will error, but
Lists.newArrayList(
"java", "-cp", ".:", "org.testng.TestNG", "-enabledefaultlisteners", "false", "testng.xml"
)
works. It seems like that should be documented in the ProcessExecutor library docs.

java.io.IOException: The system cannot find the path specified

On a particular server (Windows 2012 server R2) I am having trouble creating a temp file. I get the following error everytime I try.
java.io.IOException: The system cannot find the path specified
at java.io.WinNTFileSystem.createFileExclusively(Native Method)
at java.io.File.createTempFile(Unknown Source)
etc..
The error happens everytime the following code is ran:
InputStream inputStream = portalBean.createPDF( sessionID, foCode );
Things I have tried
Changed the java.io.tmpdir variable on the fly. System.setProperty("java.io.tmpdir", "C:\\");
Added -Djava.io.tmpdir=c:\\temp to the webnetwork lax file to an unrestricted location.
I tried setting the webNetwork service to run as a specified user with rights to temp files e.g. the Administrator.
Made sure I have free disk space and I cleaned out the c:\windows\temp folder.
Made sure the tmp environment variables were set to their default values.
I also tried running the service from a command prompt which was opened with the Run As Administrator option.
And the IOException lingers still. I have another server running the same code without issue (Windows Server 2012).
Does anyone else have any Ideas of what else I can try to resolve this issue? And or any tips on how I can debug the issue more thoroughly to get a grasp of what is going on?
One tool you can use to debug this is process monitor from system internal tool kit. The step is: add a filter to only monitor your process (I think it is javaw.exe in your case), after the error happens, go through the file activities in the process monitor log, you can find how the process is finding files and which directories the process searched. If the process is searching in the wrong directory, you can find it from the log.
I just used this tool to figure out a JVM crash problem today.
Based on the description of your problem, I guess the path variable of the process is changed in the middle of your code, with another tool process explore you can view the path variable of the process, it might help.
Try and create instead a directory somewhere under your home directory:
final Path tmpdir = Paths.get(System.getProperty("user.home"), "tmp");
Files.createDirectories(tmpdir);
System.setProperty("java.io.tmpdir", tmpdir.toAbsolutePath().toString());
Then try and Files.createTempFile() in there.
Note that if Files.createDirectories() refers to an existing file which is not a directory, you'll get a FileAlreadyExistsException.

File.createNewFile() gives java.io.IOException: Permission denied

My OS is fedora and I use the following code to create a file:
String destFile = "/var/www/html/nykkos/app/webroot/AssimilatorGenerator/Script_May6/db/"+"musics.db";
File destinationFile= new File(destFile);
if(!destinationFile.exists()) {
destinationFile.createNewFile();
}
It gives me the following exception at the line destinationFile.createNewFile()
java.io.IOException: Permission denied
Why this exception occurs and how can I overcome the same?
sudo chmod a+rwx /var/www/html/nykkos/app/webroot/AssimilatorGenerator/Script_May6/db changes the rights for all to the directory. Better look first whether chown, changing the owner/group might do. Or a combination of same group and giving the group all rights.
BTW createNewFile is seldom needed.
It is probably because the user you are running the JVM with has not the right permission to write at that path. But please post more deatils for a better answer.
You have to check owner mode and permission setting of parents directories setting. If there is no write permission in Your OS, you will get the exception.

java executing bash script, error=26 Text file busy

I've got a java code that is writing a Linux bash script out, then doing a chmod to add execute permission, then trying to execute it. I'm getting an IOException during the start of the process saying error=26, Text file busy. I've verified that the file is finished being written and the stream was closed. The chmod works fine, but I keep getting this error.
I've noticed that if I run a debugger and step through the code, it doesn't get the error, so clearly there is a timing issue involved. How can I make sure the chmod is done before I try to execute the bash script? I'd like to avoid non-reliable solutions like adding Thread.sleep(10000), and "hacky" things like putting the execution in a try/catch block inside a loop that tries until it succeeds.
I have a fair amount of code wrapping the startup of the process with listening threads, etc., but here is a simplified version of what it is doing (tried this code also and it has same result):
String[] cmd1 = {"/bin/chmod", "750", postFile };
new ProcessBuilder(cmd1).redirectErrorStream(true).start().waitFor();
String[] cmd2 = { postFile };
new ProcessBuilder(cmd2).redirectErrorStream(true).start().waitFor();
Every time after execution, the "postFile" has the correct 750 permissions, but it has not executed (due to the IOException).
For future reference, it may have been caused by an unclosed stream in this particular case, but setting permissions on a file immediately followed by running the file can cause this error too:
java.io.IOException: Cannot run program "...": error=26, Text file busy
It is a probable bug in JDK. In my case, it was caused by this snippet of code
Files.setPosixFilePermissions(Paths.get(scriptPath), set(PosixFilePermission.OWNER_EXECUTE, PosixFilePermission.OWNER_READ));
ProcessBuilder processBuilder = new ProcessBuilder(scriptPath).directory(workingDir);
processBuilder.start();
even if nothing was editing the script file.
Are you sure it is the chmod that is responsible for the subsequent error? Could you check that you definitely close the output file before you try to run it?
If you do close it then I'm at a loss why chmod should cause that error, but you could avoid the need to run chmod by using your shell to run the script:
String[] cmd = {"bash", postfile };
I don't know if it's related but usually you need to get or redirect the ErrorStream and the InputStream (I usually get them in a ResponseStreamReader that I create, don't know about the redirecting choice).
In my service file in /etc/systemd/system/ I have directed outputs to log files:
StandardOutput=file:/home/pi/ApplicationLogs/application_l_debug.log
StandardError=file:/home/pi/ApplicationLogs/application_l_error.log
The error message disappeared when I changed permissions on the ApplicationLogs directory to write permissions to all
(chmod a+w ApplicationLogs)

Categories

Resources