When I run the following command as the root user in the Centos 7 Linux terminal, it produces 57 lines of output:
journalctl --output=json-pretty UNIT=firewalld.service
So how do I change the code below to successfully call this from Java without having to leave my password in a file?
Here is my attempt. When I execute the following code, the console only outputs exit: 1:
String s;
Process p;
try {
p = Runtime.getRuntime().exec("journalctl --output=json-pretty UNIT=firewalld.service");
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
p.waitFor();
System.out.println ("exit: " + p.exitValue());
p.destroy();
} catch (Exception e) {}
Edit
When I add the following:
BufferedReader br2 = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((s = br2.readLine()) != null)
System.out.println("error line: " + s);
The following output gets generated:
error line: No journal files were found.
error line: Failed to get realtime timestamp: Cannot assign requested address
Is the problem related to permissions? When I run journalctl --output=json-pretty UNIT=firewalld.service as root from the Linux terminal, I get the 57 lines of output. But when I run journalctl --output=json-pretty UNIT=firewalld.service as a normal user, the terminal tells me that no files were found. I do not want to put my root password in Java code.
Is there some other way to call journalctl from Java without having to leave the system root password in a file?
You can add your (normal) user to the group systemd-journal using usermod -a -G systemd-journal <username>. Logout and login to it for the change to take effect. This gives your user access to the system journal files without giving it complete root privileges.
The group may be different for different operating system setups. You can simply take a look at which group the journal files belong to, by using ls -l /var/log/journal/ or ls -l /run/systemd/journal/ if /var/log/journal/ does not exist.
I have tried this in Centos LiveCD, and the group the files belonged to was root. So you can add the user to group root, which is not the same as giving it full root permissions.
Nevertheless, I suppose a better route to go would be to set ACLs on the journal files to allow a particular group to access them, because the root group may have access to a little bit too much. The manual for systemd-journald.service gives this example ACL modification command, that grants read access to the journal to wheel and adm:
setfacl -Rnm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal/
Although the manual page for journalctl tells you that adding a user to systemd-journal should allow them to access all journals, that doesn't work on CentOS 7. I have initially worked around this by doing:
chmod +s /usr/bin/journalctl
But that gives everyone access to the journals and that might not be what you want.
As #RealSkeptic pointed out the man page for systemd-journald.service indicates that additional access rights can be given to groups to read the journal (and states as well that adding a user to systemd-journal should be enough). Combining that information you can do
sudo setfacl -Rnm g:systemd-journal:rx,d:g:systemd-journal:rx /run/log/journal/
and after that adding the user to the systemd-journal group, as per the man pages, is enough to allow access to the journals:
sudo usermod -a -G systemd-journal your_user_name
Related
I am trying to use ProcessBuilder in Java and I am not quite getting how to split up my arguments for it. For example, this command + arguments find . -name 'rc*'. Here below are few different argument splits and none of them are giving me the correct result. Any idea what I am doing wrong in the argument splitting?
//This is obvious error since I mixed arugments with the command
processBuilder.command("find . -name 'rc*'").directory(new File("/etc"))
//Gives me exit code 1 and no results
processBuilder.command("find", ". -name 'rc*'").directory(new File("/etc"))
//Gives me also exit code 1 and no results
processBuilder.command("find", ".", "-name", "'rc*'").directory(new File("/etc"))
//Gives me also exit code 1 and no results
processBuilder.command("find", ". -name", "'rc*'").directory(new File("/etc"))
//Gives me also exit code 1 and no results
processBuilder.command("find", ".", "-name 'rc*'").directory(new File("/etc"))
EDIT
When I tried to add .inheritIO(), and split all arguments, to this it worked partially that is I got printouts for files that have Permission denied.
processBuilder.command("find", ". -name 'rc*'").directory(new File("/etc")).inheritIO();
but as before it did not list my other "rc" files.
Listing all rc files in /etc directory:
//Here should be at least dozen files that print out when I use the command in terminal
Exit code: 1
find 'someFileName': Permission denied
find 'someFileName': Permission denied
find 'someFileName': Permission denied
My process and printout part
Process b;
b.processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(b.getInputStream()));
String line = "";
while((line = reader.readLine()) != null){
System.out.println(line);
}
SECOND EDIT
The thing is that if I change the ProcessBuilder command to a similar command (I guess) then it prints out the resulting files with no prob with the same code - i.e. I changed the command to ls -a like
processBuilder.command("ls","-a").directory(new File("/etc")).inheritIO();
//and then activate the process and print it just as before and all good ```
The launch is from Java so there is no need to escape the find parameter rc* with single quotes. A shell such as bash would expand rc* to actual files prefixed with "rc" in the current directory (and use wrong search value), but Java will not do that. Also every parameter must be in its own string:
processBuilder.command("find", ".", "-name", "rc*").directory(new File("/etc"));
or
processBuilder.command("find", "/etc", "-name", "rc*");
If find is reporting a lot of errors you may get problem that the process freezes because you don't read STDERR at same time as STDOUT. You can choose between running threads to consume streams, or redirecting STDERR->STDOUT, or send both or merged streams to a file with Process.redirectOutput(File) and Process.redirectError(File) before calling processBuilder.start(). Read this answer.
I am creating a simple app for our users that checks if a specific user is active on a PC and returns the result.
The app consists of two parts, one will be distributed to our seniors who can set their status (meeting, break etc.), the other will be used by our juniors to check if the senior is available for helping out at any given time.
It works by running a PowerShell script which pings a PC, checks the user and stores the result in a (accessible) hashtable on a network share.
Both apps work perfectly when used by a admin, but problems arise when a normal user tries the same, it just does not run the required PS scripts.
I am 99% sure that user rights are the culprit here but I am struggling to find a simple enough solution.
I have also setup a GPO (checked the PC-s via gpresult and rsop.msc) that should theoretically allow it:
Computer Configuration > Policies > Administrative Templates > Windows Components > Windows PowerShell -- Turn on script execution -- Allow all scripts. (Unsafe, but it is for testing purposes :))
The Java code snippet that runs the script looks like this:
run_script(String path) throws IOException {
String command = String.format("powershell.exe -executionpolicy bypass -file %s",path);
String result;
Process powerShellProcess = Runtime.getRuntime().exec(command);
powerShellProcess.getOutputStream().close();
BufferedReader brd= new BufferedReader(new InputStreamReader(
powerShellProcess.getInputStream()));
while ((result= brd.readLine()) != null) {
System.out.println(result);
}
brd.close();
BufferedReader err= new BufferedReader(new InputStreamReader(
powerShellProcess.getErrorStream()));
while ((line = err.readLine()) != null) {
System.out.println(result);
}
err.close();
}
Just to repeat the important part, everything runs fine when a admin runs the app, only normal users cannot get the expected result.
And finally, my question :)
Is it possible to run code like that without admin rights on a remote PC through a Java app and are there any alternatives for getting the result I want (ping PC, check user, return result without using PowerShell)?
Thank you in advance for any suggestions and advice!
I am slowly trying to make a python script to SSH then FTP to do some manual file getting I have to do all the time. I am using Paramiko and the session seems to command, and prints the directory but my change directory command doesn't seem to work, it prints the directory I start in: /01/home/.
import paramiko
hostname = ''
port = 22
username = ''
password = ''
#selecting PROD instance, changing to data directory, checking directory
command = {
1:'ORACLE_SID=PROD',2:'cd /01/application/dataload',3:'pwd'
}
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname,port,username,password)
for key,value in command.items():
stdin,stdout,stderr=ssh.exec_command(value)
outlines=stdout.readlines()
result=''.join(outlines)
print (result)
ssh.close()
When you run exec_command multiple times, each command is executed in its own "shell". So the previous commands have no effect on an environment of the following commands.
If you need the previous commands to affect the following commands, just use an appropriate syntax of your server shell. Most *nix shells use a semicolon or an double-ampersand (with different semantics) to specify a list of commands. In your case, the ampersand is more appropriate, as it executes following commands, only if previous commands succeed:
command = "ORACLE_SID=PROD && cd /01/application/dataload && pwd"
stdin,stdout,stderr = ssh.exec_command(command)
In many cases, you do not even need to use multiple commands.
For example, instead of this sequence, that you might do when using shell interactively:
cd /path
ls
You can do:
ls /path
See also:
How to get each dependent command execution output using Paramiko exec_command
Obligatory warning: Do not use AutoAddPolicy on its own – You are losing a protection against MITM attacks by doing so. For a correct solution, see Paramiko "Unknown Server".
Well by accidentally trying something I managed to figure this out I believe. You need to do all the commands at one time and do not need to do them in a loop. for for my instance it would be
import paramiko
hostname = ''
port = 22
username = ''
password = ''
#selecting PROD instance, changing to data directory, checking directory
command = 'ORACLE_SID=PROD;cd /01/application/dataload;pwd'
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname,port,username,password)
stdin,stdout,stderr=ssh.exec_command(value)
outlines=stdout.readlines()
result=''.join(outlines)
print (result)
ssh.close()
So I'm creating a Java program and I want to make it so that you can ask it to open a program.
But, here's the catch, I want the program it opens to be taken from the user input, right now I'm trying to change this
try{Process p = Runtime.getRuntime().exec("notepad.exe");}
catch(Exception e1){}
Into something that opens a program that you asked it to open.
Here's an example of what I want:
User: Can you open chrome?
Program: Of course, here you go!
chrome opens
Could anyone tell me how I would be able to do this?
You can do it in two ways:
1.By Using Runtime:
Runtime.getRuntime().exec(...)
So, for example, on Windows,
Runtime.getRuntime().exec("C:\application.exe -arg1 -arg2");
2.By Using ProcessBuilder:
ProcessBuilder b = new ProcessBuilder("C:\application.exe", "-arg1", "-arg2");
or alternatively
List<String> params = java.util.Arrays.asList("C:\application.exe", "-arg1", "-arg2");
ProcessBuilder b = new ProcessBuilder(params);
or
ProcessBuilder b = new ProcessBuilder("C:\application.exe -arg1 -arg2");
The difference between the two is :
Runtime.getRuntime().exec(...)
takes a single string and passes it directly to a shell or cmd.exe process. The ProcessBuilder constructors, on the other hand, take a varargs array of strings or a List of strings, where each string in the array or list is assumed to be an individual argument.
So,Runtime.getRuntime.exec() will pass the line C:\application.exe -arg1 -arg2 to cmd.exe, which runs a application.exe program with the two given arguments. However, ProcessBuilder method will fail, unless there happens to be a program whose name is application.exe -arg1 -arg2 in C:.
You can try it with like. Pass whole path of where you install chrome.
try{
Process p = Runtime.getRuntime().exec("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe");
}
catch(Exception e1){
}
When using exec, it is essentially the same as if you were using the command line on windows. Open Command Prompt, type open, and see if it gives details as to how it opens files. If not, find the opener. Usually when dealing with command line operations, there are multiple parameters that are required for opening files/applications. An example of this would be for opening the "TextEdit.app" application on a mac.
Process p = Runtime.getRuntime().exec("open -a TextEdit.app");
Terminal(for mac) would open the app using the -a flag, meaning "application." You could open a file doing:
Process p = Runtime.getRuntime().exec("open filename.file_ext -a TextEdit.app");
The second one will tell the computer to find the application named <app_name>.app and open the file filename.file_ext
I know this is not going to work for a windows machine, but it's only to show how to use the command line operations for opening files and applications. It should be similar for windows though.
Hope this helps
I am unable to retrieve the output of "db2 list db directory" command in my Java program. Basically, what I am trying to do is this:-
A combo box is populated with db2 instances in the local system
User selects a particular instance from the combo box
A new Process is run to list the database for that instance
Display the database as another combo box
This is the piece of code I have done:-
// dbinstances is a Combo box (Eclipse SWT widget)
this.dbInstances.addSelectionListener(new SelectionListener() {
#Override
public void widgetSelected(SelectionEvent arg0) {
// get selected instance name
String instance = dbInstances.getText();
// command invokes db2 command window, sets current instance and issues list db command
String command = "db2cmd /c \"set DB2INSTANCE="+instance+" & db2 list db directory\"";
// execute command and read output
try{
Process p = Runtime.getRuntime().exec(command);
BufferedReader br= new BufferedReader(new InputStreamReader(p.getInputStream()));
String op = null;
while((op=br.readLine())!=null){
System.out.println(op);
}
}
catch(IOException ioe){
ioe.printStackTrace();
}
}
public void widgetDefaultSelected(SelectionEvent arg0) {}
});
The problem is that the command executes, I am unable to retrieve the output. The window just opens and closes.
One solution I tried was to redirect the output to a temporary file and read it. It works, but is quite inefficient, since this piece of code runs each time the user selects an instance.
I am running DB2 9.7 Enterprise edition on Windows XP SP3 machine.
Any thoughts on how to retrieve the output in the Java program?
Thanks a lot in advance.
You can also use the DB2 API via JNI in order to retrieve the database list directory. You have to start the scan, get the entries, and then close the scan.
By doing this, you can control the db list in a better way that parsing an output that could variate by many reasons (HADR, the authentication mechanism, local or remote, with or without alias, ip address or server name, service name or port number, in linux (home dir) or in Windows (drive letter), and other things)
The DB2 API is the same in all platforms, so it is almost platform independent, you just have to know which library load (.so or .dll), but the rest is the same.
For more information take a look at:
db2DbDirOpenScan http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.api.doc/doc/r0001509.html
db2DbDirGetNextEntry http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.api.doc/doc/r0001492.html
db2DbDirCloseScan http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.api.doc/doc/r0001437.html
Ok, figured this one out. The required solution is to add /w and /i switches to the command :-
// command invokes db2 command window, sets current instance and issues list db command
String command = "db2cmd /c /w /i \"set DB2INSTANCE="+instance+" & db2 list db directory\"";
According to IBM developerWorks
// Additional information about db2cmd Options
-c Execute the DB2 command window and terminate.
-w Wait until the DB2 command window terminates.
-i Inherit the environment from the invoking shell.
-t Inherit the title from the invoking shell