I currently have a Java based application stored on my CentOS server that is probably worth a lot of money and I need to some how give somebody access to restart the application in case it crashes without allowing them to actually get access to the java class files where they could be compromised.
Was just wondering if there's a way I could do this ? IE if there is a way I could have a jailed shell with commands restricted only to running the bash script that starts the application or if I would need to write a 3rd party application to handle all this for me?
Thanks for reading
You can absolutely have a file with the executable bit set and the readable bit not and it will do what you expect. Consider the following program:
#include <stdio.h>
int
main()
{
printf("hello, world\n");
return 0;
}
Now you can do
$ cc -o main main.c -static
$ chmod 0100 main
$ ls -l
---x------ 1 user user 821801 Sep 28 16:39 main
-rw-r----- 1 user user 75 Sep 28 16:39 main.c
$ ./main
hello, world
$ cat ./main
cat: main: Permission denied
The problem with JAR files is that they are not executables. They are not mapped into RAM by the operating system but opened and read by the JVM and it cannot do this without having read permissions set on them.
That said, your concerns are probably unwarranted. Granting world read permissions on a *.class file should be harmless. They cannot be compromised unless they are writeable which is not needed. If you store sensitive data like passwords in a *.class file, I think you should reconsider that decision.
Write a small wrapper which starts the application. The simplest way to do this would be to create a shell wrapper:
#!/bin/sh
java ...
But it's likely that that won't work on a server installation. See below.
Change the owner and group of the wrapper to a user and group which have permission to read the jar files:
$ chown user:group wrapper
Change the permissions of the wrapper to make it world-executable, and setuid (so that it will run as the owner of the wrapper, set in the previous step):
$ chmod a+rx,og-w,u+s wrapper
Then the wrapper will be run as the indicated user, without giving anybody additional privileges over the executable or its support files.
I strongly recommend not making the owner of the wrapper root. Use some user created for this purpose, which you control but which does not have root access.
In case your system doesn't honour the setuid bit for interpreters (that is, scripts with a shebang (#!) line), here's a simple C wrapper which should work. You'll have to modify it as indicated below and then compile it:
cc -Wall -o wrapper wrapper.c
(-o wrapper means "the binary to produce will be called wrapper.) Substitute whatever name you like, and put the wrapper file in a place where it can be found, such as /usr/local/bin/wrapper. It's hard to give precise instructions without knowing anything about your system configuration. Good luck.
I have no idea how you run your application, but you'll have to insert the command line into the following code, replacing java with the actual command used, and /path/to/java with the output of which java (again, use the actual command name if it isn't "java"). The arguments in the command line get inserted instead of arg1, arg2, etc. Don't use extra quotes; just the characters which form the command-line.
#include <stdio.h>
#include <unistd.h>
int main() {
execl("/path/to/java",
"java",
"arg1",
"arg2",
/* ... */
(char*)0);
/* If we get here, the exec didn't work */
perror("Failed to execute /path/to/java");
return 1;
}
If the untrusted user does not have any other access to the host on which the application is running, the above wrapper could also be used as a "restricted shell"; making it the shell of the user (or otherwise configuring ssh so that a login by that user will run the wrapper) will cause an automatic restart on login. However, that's not really a great idea, unless the application knows not to start itself up if it is already running, or can be modified to do this check. Alternatively, the wrapper could be modified to attempt to detect whether the application is currently running before restarting it. Either of these two possibilities involves more details than could be inserted into this answer.
Related
I want my directory to give executable permissions (by default) to all the shell scripts which are going to be created in that directory after I run my Java program. I tried the following commands:
setfacl -d -m group:name:rwx /path/to/your/dir
find ./ -name "*.sh" -exec chmod +x {} \;
The first one is not showing any response while the second one works fine but I have to execute this command manually in terminal after my Java program has created all the scripts. This is not what i seek. I want this thing to be automatic. Here is what I am trying to achieve:
My Java program creates the .sh files in a directory.
Now the program would try to execute this script file.
Here is a Java code snippet which shows how it is going to execute the script files:
ExecuteShellComand obj = new ExecuteShellComand();
String command2 = "./script.sh";
String output2 = obj.executeCommand(command2);
It doesn't run unless I give the executable permissions to the script.sh. How do I do it? Is there any way around it? If I am not doing something in a way it should be done, feel free to give your suggestions. Thanks
Default ACL permissions are masked by the file's creation mode as specified in open and mkdir syscalls.
Since files are usually created with a default mode of 0666, execute permissions will be masked instead of inherited.
It's the responsibility of the program that creates the files to create them with the right permissions. If you set the permissions correctly when creating the scripts, you won't need ACL or chmod at all. The best way to fix this would be for your program to set the mode in the open call to 0777.
Java appears to have Files.createFile for this. Additionally, you have a more fuzzy File.setExecutable to do it after the fact, which is not Unix canonical behavior, but probably fine for your use case.
The exec command doesn't work on my server, it does not do anything, I've had safe_mode off, and verified that all the console commands are working, I've tried with absolute paths. I've checked the permissions on the applications and all the applications I need have execution permissions. I don't know what else to do, here are the rundown of the codes I've tried.
echo exec('/usr/bin/whoami');
echo exec('whoami');
exec('whoami 2>&1',$output,$return_val);
if($return_val !== 0) {
echo 'Error<br>';
print_r($output);
}
exec('/usr/bin/whoami 2>&1',$output,$return_val);
if($return_val !== 0) {
echo 'Error<br>';
print_r($output);
}
The last two codes display:
Error
Array ( )
I've contacted the server service and they can't help me, they don't know why the exec command isn't working.
have a look at /etc/php.ini , there under:
; This directive allows you to disable certain functions for security reasons.
; It receives a comma-delimited list of function names. This directive is
; *NOT* affected by whether Safe Mode is turned On or Off.
; http://www.php.net/manual/en/ini.sect.safe-mode.php#ini.disable-functions
disable_functions =
make sure that exec is not listed like this:
disable_functions=exec
If so, remove it and restart the apache.
For easy debugging I usually like to execute the php file manually (Can request more errors without setting it in the main ini). to do so add the header:
#!/usr/bin/php
ini_set("display_errors", 1);
ini_set("track_errors", 1);
ini_set("html_errors", 1);
error_reporting(E_ALL);
to the beginning of the file, give it permissions using chmod +x myscript.php and execute it ./myscript.php. It's very heedful especially on a busy server that write a lot to the log file.
EDIT
Sounds like a permissions issue. Create a bash script that does something simple as echo "helo world" and try to run it. Make sure you have permissions for the file and for the folder containing the file. you chould just do chmod 755 just for testing.
A few more notes
For debugging always wrap your exec/shell_exec function in var_dump().
error_reporting(-1); should be on, as should be display_errors, as last resort even set_error_handler("var_dump"); - if only to see if PHP itself didn't invoke execvp or else.
Use 2>&1 (merge the shells STDERR to STDOUT stream) to see why an invocation fails.
For some cases you may need to wrap your command in an additional shell invocation:
// capture STDERR stream via standard shell
echo shell_exec("/bin/sh -c 'ffmpeg -opts 2>&1' ");
Else the log file redirect as advised by #Mike is the most recommendable approach.
Alternate between the various exec functions to uncover error messages otherwise. While they mostly do the same thing, the output return paths vary:
exec() → either returns the output as function result, or through the optional $output paramater.
Also provides a $return_var parameter, which contains the errno / exit code of the run application or shell. You might get:
ENOENT (2) - No such file
EIO (127) - IO error: file not found
// run command, conjoined stderr, output + error number
var_dump(exec("ffmpeg -h 2>&1", $output, $errno), $output, $errno));
shell_exec() → is what you want to run mostly for shell-style expressions.
Be sure to assign/print the return value with e.g. var_dump(shell_exec("..."));
`` inline backticks → are identical to shell_exec.
system() → is similar to exec, but always returns the output as function result (print it out!). Additionally allows to capture the result code.
passthru() → is another exec alternative, but always sends any STDOUT results to PHPs output buffer. Which oftentimes makes it the most fitting exec wrapper.
popen() or better proc_open() → allow to individually capture STDOUT and STDERR.
Most shell errors wind up in PHPs or Apaches error.log when not redirected. Check your syslog or Apache log if nothing yields useful error messages.
Most common issues
As mentioned by #Kuf: for outdated webhosting plans, you could still find safe_mode or disable_functions enabled. None of the PHP exec functions will work. (Best to find a better provider, else investigate "CGI" - but do not install your own PHP interpreter while unversed.)
Likewise can AppArmor / SELinux / Firejail sometimes be in place. Those limit each applications ability to spawn new processes.
The intended binary does not exist. Pretty much no webhost does have tools like ffmpeg preinstalled. You can't just run arbitrary shell commands without preparation. Some things need to be installed!
// Check if `ffmpeg` is actually there:
var_dump(shell_exec("which ffmpeg"));
The PATH is off. If you installed custom tools, you will need to ensure they're reachable. Using var_dump(shell_exec("ffmpeg -opts")) will search all common paths - or as Apache has been told/constrained (often just /bin:/usr/bin).
Check with print_r($_SERVER); what your PATH contains and if that covers the tool you wanted to run. Else you may need to adapt the server settings (/etc/apache2/envvars), or use full paths:
// run with absolute paths to binary
var_dump(shell_exec("/bin/sh -c '/usr/local/bin/ffmpeg -opts 2>&1'"));
This is somewhat subverting the shell concept. Personally I don't think this preferrable. It does make sense for security purposes though; moreover for utilizing a custom installation of course.
Permissions
In order to run a binary on BSD/Linux system, it needs to be made "executable". This is what chmod a+x ffmpeg does.
Furthermode the path to such custom binaries needs to be readable by the Apache user, which your PHP scripts run under.
More contemporary setups use PHPs builtin FPM mode (suexec+FastCGI), where your webhosting account equals what PHP runs with.
Test with SSH. It should go without saying, but before running commands through PHP, testing it in a real shell would be highly sensible. Probe with e.g. ldd ffmpeg if all lib dependencies are there, and if it works otherwise.
Use namei -m /Usr/local/bin/ffmpeg to probe the whole path, if unsure where any access permission issues might arise from.
Input values (GET, POST, FILE names, user data) that get passed as command arguments in exec strings need to be escaped with escapeshellarg().
$q = "escapeshellarg";
var_dump(shell_exec("echo {$q($_GET['text'])} | wc"));
Otherwise you'll get shell syntax errors easily; and probably exploit code installed later on...
Take care not to combine backticks with any of the *exec() functions:
$null = shell_exec(`wc file.txt`);
↑ ↑
Backticks would run the command, and leave shell_exec with the output of the already ran command. Use normal quotes for wrapping the command parameter.
Also check in a shell session how the intended program works with a different account:
sudo -u www-data gpg -k
Notably for PHP-FPM setups test with the according user id. www-data/apache are mostly just used by olden mod_php setups.
Many cmdline tools depend on some per-user configuration. This test will often reveal what's missing.
You cannot get output for background-run processes started with … & or nohup …. In such cases you definitely need to use a log file redirect exec("cmd > log.txt 2>&1 &");
On Windows
CMD invocations will not play nice with STDERR streams often.
Definitely try a Powershell script to run any CLI apps else, or use a command line like:
system("powershell -Command 'pandoc 2>&1'");
Use full paths, and prefer forward slashes always ("C:/Program Files/Whatevs/run.exe" with additional quotes if paths contain spaces).
Forward slashes work on Windows too, ever since they were introduced in MS-DOS 2.0
Figure out which service and SAM account IIS/Apache and PHP runs as. Verify it has execute permissions.
You can't run GUI apps usually. (Typical workaround is the taskscheduler or WMI invocations.)
PHP → Python, Perl
If you're invoking another scripting interpreter from PHP, then utilize any available debugging means in case of failures:
passthru("PYTHONDEBUG=2 python -vvv script.py 2>&1");
passthru("perl -w script.pl 2>&1");
passthru("ruby -wT1 script.rb 2>&1");
Or perhaps even run with any syntax -c check option first.
Since you are dropping out of the PHP context into the native shell, you are going to have a lot of issues debugging.
The best and most foolproof I have used in the past is writing the output of the script to a log file and tailing it during PHP execution.
<?php
shell_exec("filename > ~/debug.log 2>&1");
Then in a separate shell:
tail -200f ~/debug.log
When you execute your PHP script, your errors and output from your shell call will display in your debug.log file.
You can retreive the outputs and return code of the exec commands, thoses might contains informations that would explain the problem...
exec('my command', $output, $return);
I am calling a C application (console only) from my Java application.
I am calling it with: Process proc = rt.exec("./Debug/CPP_CL --device 0");
The CPP_CL needs access to clinfo() hardware .. so the GPU hardware as its processing on the GPU's. Hence, in this case needs to run as sudo/root.
Its all working fine at the moment but only if I run the Java JAR as sudo. Currently for testing only the CPG is chmod 777 (I know bad).
What I would like to know is what’s the best way to do this ? Will the CPP run as SUDO if called by SUDO java ? Or does it need to be chmod'ed ? If so what’s the best chmod value ?
Thanks.
Running Java with root is, as you said, one possibilty, but not exactly good.
The usual chmod flags (rwx) too won´t help you.
Just call it with a sudo won´t solve anything. Usually, a password is required, and if the java program can enter it (ie. it knows the root password) ... well, then it´s the same as above again.
As said in the comments, you can add a exception to sudo, but there are some catches:
You can only specify a program/script file, but no parameter limitation. You will need a script file which calls ./Debug/CPP_CL --device 0 (better with full path) and add the batch file as exception.
Furthermore, you have to make sure that the script file can´t be modified by users (chmod of the file) and can´t be deleted (chmod of the containing directory). File modification would mean that the modifying user can put anything in it and run it as root, and deletion would let the user place another file there with this name = same effect. Given that, you can call with with sudo.
If you wnat to call it without sudo, make another script file which just calls file 1 with sudo.
Another possibility is the special chmod flag SUID on the program itself (if it is enabled/supported in your distro). But here again, you can´t limit the parameters.
About the data files: A file created by a root program will be owned by root. chmod/chown as root can change that. If you only need to read the file, default umasks will allow that on many systems (if the files are in not-only-root-directories like /root)
Answer:
https://unix.stackexchange.com/questions/18830/how-to-run-a-specific-program-as-root-without-a-password-prompt
This worked.. I was able to sudo from Java and with the above no PWD is required for that application.
I am running Ubuntu 11.04.
I am trying to use a "C" execlp program to run a Java program, and then I want to setuid on the "C" program so the Java program can execute as root. There is an example of this here:
http://www.coderanch.com/t/110254/Linux-UNIX/setuid
I followed the example to the letter except instead of being the tomcat user, I used root.
Root is able to execute the "C" program which in turn executes the Java program. And, before giving root ownership, the User (me) can run the "C" program which executes the Java program. But once I setup to use setuid, and the User tries to execute the program. I get what seems to be an LD_LIBRARY_PATH type of error:
java: error while loading shared libraries: libjli.so: cannot open shared object file: No such file or directory
The libjli.so file exists under the Java JRE. Both the User and Root can see this file when they run individually. But the User cannot see it when he runs the program after setuid to root has taken place.
Is there some different way that root's LD_LIBRARY_PATH gets set when a setuid program executes? Is this an interactive vs. non-interactive problem?
Any ideas? Thanks in advance.
As the LD_* environment variables can be used to load code into a process, they are all ignored by setuid binaries. You will probably need to make the setuid binary a wrapper which executes the C program.
Setting the setuid bit on a file will change the process's effective UID but not the real UID. The dynamic linker will check to see if EUID ≠ RUID, and if so, it will ignore all environment variables. Your wrapper will have to filter the environment variables itself (important!) and once done, change the real UID to match the effective UID.
Warning: Don't forget to scrub the environment variables well, unless you are okay with giving everyone on the box full root access.
To work around the LD_* environment constraints on setuid programs, on most POSIX systems you should be able to do this within your wrapper code:
setreuid(0, 0);
which will set both the real and effective UIDs to be root, although this will only work if the program itself was started with the setuid bit enabled.
I wouldn't do it, though.
Look at why your Java program needs to run as root, and see if there are better ways to give it the privileges it needs without actually running as root.
I am trying to run a perl command with Java runtime exec in linux/ubuntu/gnome. The command generates an pdf file, but it saves it in my home folder. Is there any way that the exec method can set an output path for the commands executed? Thanks in advance.
The exec method just runs the command on the operating system, so you'll want to change the command you're running with exec more than anything in "Java" per se.
There are a few possibilities:
Change the working directory of your java program. The .pdf is being saved in your working directory because this is where the program is being run.
Unfortunately it's not simple to change this value after the program has been launched. It is, however, trivial to change before the program starts; just change the working directory before starting the program.
Move the file to it's desired location after it's been created in your home directory.
Change the command so that it includes the target location. Your perl script may have an option that will enable you to save it's output to a certain location (usually -o or --output). Using this your program would change from:
Runtime.exec("perl someprogram");
to something like:
Runtime.exec("perl someprogram -o /path/to/some.file")
You might be able to use "output redirection", if there is no option to do this.
Try something like what's below as your argument:
Runtime.exec("perl someprogram > /path/to/some.file")
Unfortunately, without knowing more details of your situation I can't provide more concrete advice.
While each approach has benefits and drawbacks, it's probably best to just implement the one that you understand best; if you can't get one to work, try another.
A good, free online resource for learning is Introduction to Linux: A Hands On Guide.
Section 2.2 has details on cd which you can use for 1..
Section 3.3, section 3 teaches about the mv command, which will be useful in 2..
Section 5.1 is about I/O redirection. Knowing about "output redirection" and the > operator, are important for 4..
For 3., you'll have to consult the documentation of the perl program you're using.
You could modify the Perl script to accept an absolute path for the output.
You can trying setting the working directory using exec(java.lang.String[], java.lang.String[], java.io.File) where File is the directory the command is executed from.
If all else fails, you'll can always copy the generated file from the Home directory to your final location.