I have a web application that runs as a user www. However at one point it needs to read a file from a Linux filesystem on behalf of users Alice and Bob.
One way of doing this would be to launch a shell (Runtime.exec()) and call a C setuid executable to change userid and read the file.
Is there a way to achieve this with JNI (the web app needs to run as www and not root)? I tried to write a Java JNI program that calls native methods on Linux (I made these native methods owned by root and have setuid bits set). But unless I run the Java program as root, it does not let me switch user ids. Is there something that I am missing? Is there a way to achieve this?
Thanks!
No. There is not. setuid and setgid can only be used in two cases (on ordinary Linux):
The process is root.
The process was launched from a file with the setuid or setgid bits in its modes.
In the former case, the process may call these functions willy-nilly to adopt any identity. In the later case, the process my only switch back and forth between the uid/gid of the parent and the uid/gid of the file it was launched from.
That is, if setuid, it may adopt the uid of the file, if setgid, the gid.
Since you are in java, the exec-ed program is java itself, and you don't want that to be setuid or setgid, not unless you want to create a colossal security exposure.
You could write a C or C++ program that started the JVM via the JNI invocation interface, and set that program to be setuid or setgid, and then JNI code invoked in there could make the appropriate calls to switch.
Yep, it's possible. You can see an example here:
https://github.com/kebernet/pretty/blob/master/src/main/java/com/reachcall/util/SetUID.java
Here's example of the code:
CLibrary INSTANCE = (CLibrary) Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
public static int setuid(int uid) {
if (Platform.isWindows()) {
return OK;
}
return CLibrary.INSTANCE.setuid(uid);
}
bmargulies's answer is not correct (or not quite correct).
A non-root process in UNIX can set uid or gid, if it has respective capabilities:
http://man7.org/linux/man-pages/man7/capabilities.7.html
CAP_SETUID
Make arbitrary manipulations of process UIDs (setuid(2),
setreuid(2), setresuid(2), setfsuid(2));
Since from OS prospective, your program is running as "java" process, this setguid capability must be enabled for the java executable itself:
$ sudo setcap cap_setuid,cap_setgid+ep /usr/java/latest/bin/java
Also notice that filesystem where java executable resides, isn't mounted with "nosuid" option.
Back to your original question
the web app needs to run as www and not root
Normally it's not a good idea to let web service to have a setuid capability.
It's better to drop uid in a shell wrapper script that starts up your web application.
Related
I'm wondering if it's possible to run a .exe from A web-server using the domain name as parameter.
It's working fine using a network shared folder
Process x = new ProcessBuilder("http://example.com/MAJ.exe","param1","param2").start();
Absolutely not. The javajavadoc is straight forward:
Constructs a process builder with the specified operating system program and arguments. This constructor does not make a copy of the command list. Subsequent updates to the list will be reflected in the state of the process builder. It is not checked whether command corresponds to a valid operating system command.
That constructor takes a command and arguments to that (as strings). It doesn't take a URL. It is as simple as that. This interface is intended to run a command that exists in the local machine, file system.
Also note the major conceptual flaws here:
what does it mean to run an EXE that lives on a server?
do you want to download it and run it locally?
or should the server invoke it? In what context? Where would the results go?....
So, the real answer is:
either you should provide a service to download that executable to your local machine, to run it locally
or your wrap that executable into some form of service that you can invoke remotely (like any other restful HTTP(S) service)
From what I read, there are a couple of ways to run java files in a node.js application. One way is to spawn a child process: (the java code is packaged with dependencies in an executable jar.)
var exec = require('child_process').exec, child;
child = exec('java -jar file.jar arg1 arg2',
function (error, stdout, stderr){
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if(error !== null){
console.log('exec error: ' + error);
}
});
The other way is to use the java - npm module (link), a wrapper over JNI (this will let me create objects, set and get attributes, run methods).
In a production environment, when I want my node.js (Express) server to call a java program (it just saves an image to the local directory), please advise me on which would be the better way to accomplish this (in terms of best practices). Also, there is a long list of arguments that I need to pass to the main class and doing that on the command line is a bit of a struggle. Should I make the java program read from an input file instead?
1) If you use exec, you will run an entire program, whereas if you use a JNI interface, you'll be able to directly interact with the libraries and classes in the jar and do things like call a single function or create an instance of a class. However, if you don't need anything like that, I think using exec is far simpler and will also run faster. Sounds like you just want to run the Java application as a standalone process, and just log whether the application finished successfully or with errors. I'd say it's probably better to just use exec for that. Executing a child process this way is also far better for debugging, debugging JNI errors can be very difficult sometimes.
2) As for whether or not to read arguments from a file, yes, it's usually better to read from some sort of file as opposed to passing in arguments directly. It's less prone to human error (ie. typing in arguments every time), and far more configurable. If someone like a QA engineer only needs to edit a config file to swap out options, they don't need to understand your entire codebase to test it. Personally I use config files for every Java program I write.
You can use deployment toolkit and run the jar through jnlp. https://docs.oracle.com/javase/8/docs/technotes/guides/deploy/deployment_toolkit.html
Advantage of running jars through jnlp is the ability to pass parameters from javascript to your jar. In this way you can dynamically customize your java program.
For this kind of problem you'd want to approach it in the following way:
Is there a decent way to run processes with arguments in my language/framework
Is there a decent way to deal with the programs output?
From experience, a decent way to deal with arguments in a process is to pass them as an (string) array. This is advantageous in that you do not have to resort to unnecessary string interpolation and manipulation. It is also more readable too which is a plus in this problem setting.
A decent way to deal with output is to use a listener/event based model. This way, you respond appropriately to the events instead of having if blocks for stderr and stdout. Again, this makes things readable and let's you handle output in a more maintainable manner.
If you go a bit further into this, you will also have to solve a problem of how to inject environment variables into your target program. As an example, you might want to run the java with a debugger or with less memory in the future, so your solution would also need to cater for this.
This is just one way of solving this kind of problem. If node is your platform, then have a look at Child Process which supports all of these techniques.
We can run the whole java project by making .jar file of it and run it using the command in the shell and run that shell file. In order to run java code from nodejs project as we know project could be a mix of java, js modules.
Call exec() function in node to create a child process to execute the shell file having a command to run .sh file and can also pass some argument in it from use.eg;
let fileName = 'someFile.txt';
let userName = 'Charlie Angle';
exec(`sh run.sh --context_param
paramFilePath="./storage/${fileName}" --context_param userName="${userName}"`, (error, stdout, stderr) => {// Some code based on execution of above command})
You can simply call a java command , with classpath & arguments, using module node-java-caller, it embeds the call to spawn and will also automatically install java if not present on the system
https://github.com/nvuillam/node-java-caller
Original message
I'm currently working on several executable Jars being called by another Java process (or "Launcher) called by a scheduler.
To do this, we use ProcessBuilder. However, we need to be able to share variable between the parent process and the child process (The executable JAR).
I know it's possible to pass variable to the child process with the environment() method.
What we need is to be able to share informations from the child process to the parent process (the process results, mostly files). Is it possible? If it is, how so?
Update
The two java processes are on the same computer and so share the same disk space. The Launcher process is called by a scheduler and this process cannot be changed.
I know that using a file is probably the best solution but I was wondering if there was no other solution.
Thanks in advance for your help.
A process is a sort of black box with which you can dialogue only via standard streams (input, output, error) or retrieving exit code of the process.
All other systems needs an external way to communicate.
So you can:
Use the method exitValue() of the Process as a form of communication between child and parent.
Intercept the output of the child process using the getInputStream() method.
Share data with external resources (files, databases or opening communication sockets for example).
You need bidirectional communication between processes. You can choose from three alternatives:
Asynchronous low level: Use a pre-stablished disk file for each communication: One file to write data from each child process to the parent process, and another to write data from the parent process to the child process (if needed).
Synchronous generic server/client level: On every process that must receive data (either the parent process or either each child process), open a ServerSocket and accept requests according to your own protocol (typically this must be done on a secondary thread).
Synchronous specific Java RMI level: This is the most advanced, flexible and usable alternative you can get: Design and implement an RMI interface and deploy it as a server on each process that must receive data, and also deploy it as client on each process that must send data.
What you need to do is not to execute your process directly, but rather create a (batch) script which executes the command and after this it writes the value of the variable to a file. Then make the ProcessBuilder execute the (batch) script.
Then, before calling another process, read the file, and pass the variable value to the ProcessBuilder using the environment() method you mention.
So the (batch) script looks as follows:
<your command>
echo $variable > file.txt
And then you execute shell with the script filename as an argument:
bash batchscript.sh
In windows, it works the same, except you want to execute
cmd /c batchscript.cmd
There was a product called Terracotta that allowed to share object across multiple JVM instances.
The onwer company still have open source versions of their products but I don't know them anymore.
If you want to use RMI as suggested by Little Santi you may use Spring-remoting to make it easier.
I want to hide arguments (password paraphrase) from a running java process (can be seen from command line).
For example, when i type jps -m on cmd, it shows me all the java processes along with their arguments:
Output after running jps -m: 6120 someproject.jar -password
where 6210 is pid.
I need that password to run java process. The problem is if my machine is compromised, someone could read password and can do further damage.
One solution could be storing password in a file locally. But still someone can get it if machine is compromised.
Any ideas how i proceed ?
Thanks in advance.
update1: The password is hashed but still i want it to hide.
The way you would handle this in (for example) a C program would be to write over the argument list supplied to the main(...) entry point method. For more information read this:
https://unix.stackexchange.com/questions/8223/can-other-users-view-the-arguments-passed-to-a-command
Unfortunately, the "overwrite" approach is not available to a Java application. From pure Java, it is simply not possible. Even with native code library, it would be difficult to find where in memory the (native) argument vector is stored.
(And besides, there is a small time window in which the arguments are exposed ... before the application erases them.)
So your best bet is to pass the secret information another way. For example, pass the secret info via an environment variable, via a temporary file with access restrictions, or via standard input.
I have a Java program that is mostly GUI and it shows data that is written to an xml file from a c++ command line tool. Now I want to add a button to the java program to refresh the data. This means that my program has to call the c++ functionality.
Is the best way to just call the program from java through a system call?
The c++ program will be compiled for mac os and windows and should always be in the same directory as the java program.
I would like to generate an executable can the c program be stored inside the jar and called from my program?
If you have access to the code and want an 'interactive' experience with the external program (e.g., make call, get results, make additional calls), investigate JNI, which allows you to call C or C++ code from a Java application by including & linking JNI juice to your C or C++ app with .
See:
http://en.wikipedia.org/wiki/Java_Native_Interface
http://www.acm.org/crossroads/xrds4-2/jni.html
If you really just need a "launch app and get results" sort of solution, check out Runtime.exec(), which lets you launch an external program & capture its output.
See:
http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=1
http://www.rgagnon.com/javadetails/java-0014.html
Assuming no better communication method is available (SOAP, ICE, Sockets, etc), I'd call the executable using Runtime.exec(). JNI can be used to interface directly, but I wouldn't recommended it. No you can't put an executable in the jar. Well you can, but you can't run it, since the shell doesn't know how to run it.
You may also want to look at the Java Native Access API (JNA).
To answer your final question, you can't run an executable from within your jar.
However, you can store it within your jar and extract it to a temporary directory/file prior to running it (check for its presence the first time and extract if necessary). This will simplify your distribution somewhat, in that you only have the jar to distribute, and ensures that you're running an executable that matches your jarred Java code.