Enforcing specific command arguments for a selected user with sudo

In one of my last articles I needed to enforce the execution of a command with certain arguments – specific for the present user. I.e., I wanted to take away the freedom of the user to set arbitrary command argument(s) as he/she liked.

This had to be done in addition to another set of rules – namely a bunch of iptables filter rules which also depended on the UID. So the command had to be run with the UID of the user him/herself and not with the UID of root.

The solution came with sudo. This may appear a bit surprising to some readers. The reason is that sudo normally is used to allow selected users to run commands with another UID than the one they have themselves. I call “the other user” the “effective user” below. In a sudo context the effective user corresponds to a SUDO_UID variable in addition to the UID environment variable. The predominant example for invoking the sudo-mechanism certainly is to allow users to run a command as root. But it can be extended to any other user (made harmless by taking away hsi/her login shell or being especially privileged due to membership in a special group).

In my case I needed to enforce command execution with an effective user being identical to the original user him/herself – but with special arguments. In such a situation you have to take take the permission to execute/read the original command completely away from the user. Otherwise he/she could use it with any argument. But sudo requires that the defined effective user is able to read and execute the command. This seemingly contradictory situation can be solved by invoking a special user-group.

Maybe the recipe described below helps some readers to enforce command execution with specific arguments in other contexts.

A simple scenario

Let us assume you have developed a program “myprog” which accesses special web-service that you have installed on some web-servers in your Intranet. Let us further assume that some specific users shall be restricted to access the service on a defined server only – and there only with certain arguments. Such parameters may reduce or give rights to access certain data the service could in principle provide. All this is regulated by 2 arguments to the myprog-program: a FQDN for the host and a “level”. “level 0” allows free access to a very basic service version. “level 1” invokes the program with personalized options and requires a login. But your people have started to play around with the Login. So, you want a group of users to issue the command with a certain “host” and “level 0” only. Let us assume that user “mark” is one of those users who should invoke the command only in the form

mark@mytux:~>myprog -h myserv.anraconc.de -L 0

How can we achieve this with sudo?

Restricting command use to specific arguments

Below I discuss modifications of the “/etc/sudoer” file. This is risky in very many ways – not only regarding security.

Disclaimer: I take no responsibility whatever for the consequences of the sudo approach described below and its application to your computers. The sudoer rules have to be tested carefully before the are used in a production environment and their setup must be supervised by an expert.

I assume that you have installed your program at the path “/usr/bin/myprog” with standard rights

-rwxr-xr-x 1 root root 334336 17. Mai 2020  /usr/bin/myprog

Then one can follow the following recipe (as root) to get “mark” under control:

  • Step 1: Create a special group for the command in question, e.g. “mygroup”. Ensure that mark does not become a member of this group.
  • Step 2: Change the ownership and access rights of “/
    usr/bin/myprog” according to
    • chown root.mygroup /usr/bin/myprog
    • chmod 750 /usr/bin/myprog
  • Step 3: Add some lines to “/etc/sudoers” (with visudo):
     
    ....
    Defaults env_reset
    Defaults env_keep = "LANG LC_ADDRESS LC_CTYPE LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE LC_ATIME LC_ALL LANGUAGE LINGUAS XDG_SESSION_COOKIE"
    
    Defaults:mark env_keep += "DISPLAY"
    
    #Defaults targetpw   # ask for the password of the effective target user e.g. root
    #ALL   ALL=(ALL) ALL
    
    mark ALL=(mark:mygroup) /usr/bin/myprog -h mysrv.anraconc.de -L 0
    ....
    

Explanation:
Due to step 2 user “mark” cannot read, change or execute the command directly any longer. The rest depends a bit on ensuring the “mark” never becomes a member of group “mygroup”. (But other users which you trust may become members.)

Regarding the sudoer rules I assumed that you reset the environment of a sudo user as a default. Keeping up the “DISPLAY” variable helps to get around some access problems with the present X11-screen of “mark”. I also assumed that you use the sudo-mechanism in a way which requests that the user enters his/her password. The last line allows “mark” on all hosts/terminals to execute “/usr/bin/myprog” as him/herself, but with the GID of group “mygroup” and exactly with the options “-h mysrv.anraconc.de -L 0”.

Note that sudo compares the command including arguments as one string!

User “mark” must run the command myprog from now on in the form:

sudo -u mark -g mygroup  myprog -h myserv.anraconc.de -L 0

and enter his password. Any deviation will be blocked by the sudoer mechanism.

Some practical hints

After carefully evaluating security implications you can make life easier for “mark” in two ways:

  • Let him execute the command (with the defined arguments) without providing a password. Use the NOPASSWD attribute; see the man pages for the sudoers file.
  • Write a script which encapsulates the described sudo command with the options.

By such measures, you may save “mark” some typing time.

Another point is to keep the file permissions up in the future. This may become a problem if and when you apply the described mechanism to some standard Linux commands which are installed and updated by some package administration tool of your distribution. You have to carefully check that the installation routines do not overwrite the permission settings! A handwritten systemd service or a cron job may help you with this task.

With some reading or experience it should be easy to extend the described recipe to groups of users and to other commands.

There are multiple ways to allow other users to execute the command freely if this should be required. The sudoer file knows about a logical NOT operator (!); this helps to add a sudoer rule for all users but NOT “mark”. Another simple approach would be to add all users but “mark” to the group “mygroup”.

Conclusion

The sudoer-mechanism is a mighty Linux tool. We can not only allow users to execute commands as another user, but also with the permissions of another group. AND we can enforce the usage of commands with predefined arguments for selected users or user groups.

As fiddling with the sudoer mechanism is always a bit risky: Please, write me a mail if you find some major mistake or security problem of my approach.

KVM/Qemu VMs with a multi-screen Spice console – VIII – VM and user specific restrictions for remote-viewer connections – iptables and sudo

The Spice console allows users to access the graphical desktop of a Qemu based virtual machines [VM]. The performance with both data encryption and data compression is excellent, audio is no problem and the required data transfer rates to client-applications as “remote-viewer” are within reasonable limits for a (switched) LAN. In virtualization scenarios where you can organize tasks according to a scheme “one user per VM” Spice is actually an attractive tool – and even professional virtualization environments a “Proxmoxx” and “oVirt” make use of it.

In this series we look at basic setups in self-administered Intranet environments. So far we had some ups and downs regarding the tool remote-viewer. If you want to use it in a desktop virtualization environment it is an almost perfect tool. We also found it to be a very convenient and efficient remote client-tool in an Intranet when we combined it with SSH and internal data compression of the Spice protocol. See:

KVM/Qemu VMs with a multi-screen Spice console – V – remote access via remote-viewer, a network port and a SSH-tunnel
KVM/Qemu VMs with a multi-screen Spice console – IV – remote access via SSH, remote-viewer and a Unix socket
KVM/Qemu VMs with a multi-screen Spice console – III – local access with remote-viewer via a Unix socket

SSH gave us all options we needed to take care of various security issues in remote access scenarios. The KVM/Qemu server could control the interaction of remote-users with VMs by applying user-specific SSH restrictions to port-forwarding. We could establish rules to bind the Spice access to a specific VM to a specific user.

Regarding the last point the combination of remote-viewer, TLS and SASL came as a solid disappointment. TLS worked perfectly. But we had problems with SASL; see:

KVM/Qemu VMs with a multi-screen Spice console – VII – remote-viewer, qemu and SASL authentication
KVM/Qemu VMs with a multi-screen Spice console – VI – remote access with remote-viewer and TLS encryption

We got SASL authentication working in two different ways. The frustrating result of our efforts, however, was that we could not confine the access to the Spice-console of a specific VM to exactly one user.

In the end we found that it might even be better to use TLS and a VM-specific Spice password set in the VM’s XML-domain file. The problem then still is that users could share the password for a specific VM. So, we still could not ensure a scenario “one VM – one UID, only”.

In this article we, therefore, look at measures on remote client-systems to allow a TLS connection to a specific VM on the KVM/Qemu host for exactly one user. We use two different Linux tools – namely iptables and sudo – to achieve this. The recipes given below are interesting in themselves and can be applied to other scenarios where the admin wants to restrict outgoing TCP-connection on a user specific level.

Why do we care about user-specific control for Spice at all?

Assume a situation
in a small Linux oriented office where you run a bunch of VMs for special purposes on a central KVM-server.
You provide e.g. a VM (VM1) with Windows 10 ( 🙁 ) for book-keeping with a program your tax advisor understands. A user “Charlie” with a defined UID should use the VM’s Spice console, but basically only he (and his boss in the evening hours).
You have a second VM (VM2) with a Web-server for development and test purposes. Only user “Maggie” shall have access to the Spice console of VM2 on Mondays and Tuesdays and a user “Anne” on Wednesdays and Thursdays and no one else.
And then there is yet another VM (VM3) which only user “Ralph” shall access via Spice to create documents of a confidential analysis for a governmental organization.
There are multiple Linux client PCs available in the office; any of the user can use and login to any free Linux workstations. None of the user has root rights on the clients and the server.

We have thus defined a scenario of the type

One VM + Spice console    < = >    one user or a group of selected users.

Can you cover such a situation with remote-viewer, TLS and server-based SASL, only?
The answer of my last article was: NO. At least not by simple means. (By the way: It is not the fault of SASL. Remote-viewer, simply and unfortunately, does not provide any system-based data for the realm or for the remote-system which SASL could evaluate. The user has too much freedom …)

Do we need measures on the client-systems?

It is interesting that even Opensuse’s “Virtualization Guide” writes about some required measures on the client (restricting access to specific client-certificates for selected users) when discussing the security for libvirt and vnc as tools to access the graphical desktop of a VM. We have not come to libvirt-based tools in this series, yet, but this is already some indication that restrictions of desktop access to KVM/Qemu based VMs may sometimes require measures on the client. So, let us turn to the client-systems … Of course, we assume that such clients have a Linux OS, in my case a Opensuse Leap 15.2.

Schematic drawing

The following schematic drawing reflects the situation we want to control:
We want to make it impossible user “mybro” to access the Spice console of a VM1. Only “myself” should be able to use VM1’s Spice console via a TLS connection. The other way round: Only user “mybro” shall be allowed to connect to the the Spice console of VM2 with remote-viewer. Cross-connections are forbidden; each user gets access to one defined VM only.

We use the same systems as in the last articles: A KVM/Qemu server host “MySRV” (IP: 192.168.2.2) with a Leap 15.2 OS on it, a test-VM1 “debianx” with a Kali-OS on it and a client-system “MyLAP” (a laptop with a Leap 15.2 OS; IP: 192.168.2.22). On MyLap we have a user “myself” and a user “mybro”. VM1 (“debianx”) gets the (TLS-) port 20002 on the server, and VM2 (“leaptest”) the (TLS-) port 20004.

We shall perform the experiments in this article with a Qemu set up without SASL, but each VM configured for an individual password. (As we already know it will only means a small difference in the form of the authentication dialog. We will not be asked for a username.) The scenario can easily be changed to SASL authentication.

Strategies to allow Spice access to a VM’s desktop only for a specific user

There are three major strategies we can follow:

Strategy 1: We could think about a specific TLS client certificate for a connection to a VM and to make it accessible only to the user in question. Such a
strategy would require that client certificates are supported by Qemu and Spice.

Strategy 2: We could use iptables and add user-specific rules for outgoing data to certain TLS-ports on the server. As user-related rules can only be set for the “output chain” we cannot set any such user-specific filters for our problem on the server.

Strategy 3: We take the choice of the target port on the server away from the user as well as any free access to the remote-viewer command namely by changing file permissions, setting up special sudo rules and/or enforcing him/her to run a shell script which starts remote-viewer with a pre-defined target port for him/her.

The strategies (if working) can be combined. Even if the firewall of strategy 2 failed the user would only get access to a specific VM by restrictions of strategy 3. But all these things are a bit complicated and they all depend on the user not being able to get root rights, the firewall being set up at every system-startup and the sudo rules being tight. This is crucial; our KVM/Qemu server with TLS and SASL could only block connections from certain IPs, but not really users.

We could extend strategy 3 to a network namespace – but it won’t help too much as we then would again need to apply routing and related firewall rules. Or to sudo rules. We could also think about using different networks for different VMs and thus a port-IP-VM-relation – but we would still depend on user-specific firewall rules on the clients.

Strategy 1: What about Spice and TLS client certificates?

Here I come with bad news:
If you activate the option “default_tls_x509_verify = 1” in “/etc/livirt/qemu.conf” it is simply ignored. One can guess it from a lack of required parameters in the qemu-command created by virt-manager. Even if and when you provide client certificates in the required directories on the server and the client. In contrast to VNC-settings there is no option like “spice_tls_x509_verify = 1” available. If you set it by yourself, it is silently ignored.

So, client-certificates will be of no help with Spice and remote-viewer. The situation my be different for the libvirt-dependent “virt-viewer” tool. But this is the topic of a future blog post.

Strategy 2: netfilter/iptables to the rescue

I assume that you have some tool in place on your Linux systems to configure your own iptables-rules. Professionals may write their own scripts. Independent of your interface to netfilter/iptables, it is obvious that working with firewall rules in a productive environment is a risky business. Therefore:

Disclaimer: I take no responsibility whatever for the consequences of the approach describes below and its application to your computers. The iptables-rules have to be tested carefully before making them productive and their setup on Linux hosts must be supervised by an expert.

In my network environments I still cling to the tool “fwbuilder” because it gives you a good graphical overview for most purposes and it allows for more complex configurations than e.g. frontends to firewalld or ufw. So, let me show you how to set up a basic set of user-specific iptables rules with fwbuilder and then have a closer look at the contents of the created statements of the firewall script.

fwbuilder allows you to set up “users” with a defined UID in the object catalog for “services”:

This may seem strange; but the meaning is the following:

  1. Using a “user” as a “service” will trigger the creation of a rule for the OUTPUT chain which matches the user of outgoing connection
    packets against an owner with a defined UID and then triggers a reaction.
  2. To cover the reaction in fwbuilder we “branch off” into a specific rule-set for the user. On the iptables level this corresponds to a user-defined rule-chain as a reaction target.
  3. The filter-rules for data packets in the user-defined chain themselves then lead to certain final reactions in the sense of “allow” or “deny”.

In pseudo-code: IF a user matches an UID THEN apply a set of filter rules with their own final reactions.

In Fwbuilder a set of filter-rules is usually put into an object called “policy”. The following image shows some rules of the main “policy” on “MyLap”:

You see that rules 4 and 5 include users “myself” and “mybro”; the rules branch off to policies “Spice_VM_1” and “Spice_VM_2”, respectively.

Rule 6 blocks a whole bunch of TCP-ports used for VMs on the KVM/Qemu server for any other user than “myself” and “mybro”.

Policy “Spice_VM_1” contains one rule, only:

This rule specifies a certain interface and the IP of the target host “mysrv”. We allow access to port 20002 – corresponding to the TLS port defined for our test VM “debianx” (VM1). Something analogous holds for our second user “mybro”. He gets access to another virtual machine “VM2” which we have bound to port 20004 on the KVM-server for external TLS connections.

Now, let us look at the iptables statements generated by fwbuilder:


    # ================ Table 'filter', automatic rules
    # accept established sessions
    $IPTABLES -A INPUT   -m state --state ESTABLISHED,RELATED -j ACCEPT 
    $IPTABLES -A OUTPUT  -m state --state ESTABLISHED,RELATED -j ACCEPT 
    $IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT 
    # backup ssh access from a admin host 
    $IPTABLES -A INPUT  -p tcp -m tcp  -s 192.168.44.12/255.255.255.255  --dport 22  -m state --state NEW,ESTABLISHED -j  ACCEPT 
    $IPTABLES -A OUTPUT  -p tcp -m tcp  -d 192.168.44.12/255.255.255.255  --sport 22  -m state --state ESTABLISHED,RELATED -j ACCEPT


    # ================ Table 'filter', rule set Spice_VM_1
    # 
    # Rule Spice_VM_1 0 (eth0)
    # 
    echo "Rule Spice_VM_1 0 (eth0)"
    # 
    $IPTABLES -N Spice_VM_1
    $IPTABLES -N Cid40091X30615.0
    $IPTABLES -A Spice_VM_1 -o eth0  -p tcp -m tcp  -d 192.168.2.2   --dport 20002  -m state --state NEW  -j Cid40091X30615.0
    $IPTABLES -A Cid40091X30615.0  -s 192.168.2.22   -j ACCEPT
    $IPTABLES -A Cid40091X30615.0  -s 192.168.2.22   -j ACCEPT
    
    # ================ Table 'filter', rule set Spice_VM_2
    # 
    # Rule Spice_VM_2 0 (eth0)
    # 
    echo "Rule Spice_VM_2 0 (eth0)"
    # 
    $IPTABLES -N Spice_VM_2
    $IPTABLES -N Cid40661X30615.0
    $IPTABLES -A Spice_VM_2 -o eth0  -p tcp -m tcp  -d 192.168.2.2   --dport 20004  -m state --state NEW  -j Cid40661X30615.0
    $IPTABLES -A Cid40661X30615.0  -s 192.168.2.22   -j ACCEPT
    $IPTABLES -A Cid40661X30615.0  -s 192.168.2.22 
  -j ACCEPT
    
    # ================ Table 'filter', rule set Main_Policy
    # 
    # Rule Main_Policy 0 (eth0)
    # 
    echo "Rule Main_Policy 0 (eth0)"
    # 
    # Antispoofing
    $IPTABLES -N In_Main_Policy_0
    $IPTABLES -A INPUT -i eth0   -s 192.168.2.22   -j In_Main_Policy_0
    $IPTABLES -A INPUT -i eth0   -s 192.168.4.22   -j In_Main_Policy_0
    $IPTABLES -A FORWARD -i eth0   -s 192.168.2.22   -j In_Main_Policy_0
    $IPTABLES -A FORWARD -i eth0   -s 192.168.4.22   -j In_Main_Policy_0
    $IPTABLES -A In_Main_Policy_0  -j LOG  --log-level info --log-prefix "RULE 0 -- DENY "
    $IPTABLES -A In_Main_Policy_0  -j DROP
    # 
    # Rule Main_Policy 1 (lo)
    # 
    echo "Rule Main_Policy 1 (lo)"
    # 
    $IPTABLES -A INPUT -i lo   -m state --state NEW  -j ACCEPT
    $IPTABLES -A OUTPUT -o lo   -m state --state NEW  -j ACCEPT
    # 
    # Rule Main_Policy 2 (global)
    # 
    echo "Rule Main_Policy 2 (global)"
    # 
    #  ICMP, DNS, DHCP 
    $IPTABLES -A OUTPUT -p icmp  -m icmp  --icmp-type 3  -m state --state NEW  -j ACCEPT
    $IPTABLES -A OUTPUT -p icmp  -m icmp  --icmp-type 0/0   -m state --state NEW  -j ACCEPT
    $IPTABLES -A OUTPUT -p icmp  -m icmp  --icmp-type 8/0   -m state --state NEW  -j ACCEPT
    $IPTABLES -A OUTPUT -p icmp  -m icmp  --icmp-type 11/0   -m state --state NEW  -j ACCEPT
    $IPTABLES -A OUTPUT -p icmp  -m icmp  --icmp-type 11/1   -m state --state NEW  -j ACCEPT
    $IPTABLES -A OUTPUT -p tcp -m tcp  --dport 53  -m state --state NEW  -j ACCEPT
    $IPTABLES -A OUTPUT -p udp -m udp  -m multiport  --dports 68,67,53  -m state --state NEW  -j ACCEPT
    # 
    # Rule Main_Policy 3 (global)
    # 
    echo "Rule Main_Policy 3 (global)"
    # 
    $IPTABLES -A OUTPUT -p udp -m udp  --dport 123  -m state --state NEW  -j ACCEPT
    # 
    # Rule Main_Policy 4 (global)
    # 
    echo "Rule Main_Policy 4 (global)"
    # 
    $IPTABLES -A OUTPUT -m owner --uid-owner 1021  -j Spice_VM_1
    # 
    # Rule Main_Policy 5 (global)
    # 
    echo "Rule Main_Policy 5 (global)"
    # 
    $IPTABLES -A OUTPUT -m owner --uid-owner 1022  -j Spice_VM_2
    # 
    # Rule Main_Policy 6 (global)
    # 
    echo "Rule Main_Policy 6 (global)"
    # 
    $IPTABLES -N Out_Main_Policy_6
    $IPTABLES -A OUTPUT -p tcp -m tcp  --dport 20001:20010  -j Out_Main_Policy_6
    $IPTABLES -A Out_Main_Policy_6  -j LOG  --log-level info --log-prefix "RULE 6 -- DENY "
    $IPTABLES -A Out_Main_Policy_6  -j DROP
    # 
...
...

 
These are simple rules which the experienced reader will have no difficulty to interpret. (The reader also sees that I have multiple IPs on eth0, but this does not affect our present topic).

I leave the test to you. You should see that user “myself” can access VM1 (debianx) whilst user “mybro” and any other users cannot. User “mybro” instead can access VM2 on the server.

Important note:

Do not forget to write a small systemd service which starts your firewall automatically during the startup of your client-system.

I have written about his topic somewhere else in this blog already. believe me its easy.

Strategy 3: Using sudo

Working with “sudo” and manipulating the file “/etc/sudoers” is somewhat risky. Therefore:

Disclaimer: I take no responsibility whatever for the consequences of the sudo approach describe below and its application to your computers. The sudoer rules have to be tested carefully before the are used in a production environment and their setup must be supervised by an expert.

The settings below work for an Opensuse Leap system – partially due to the default settings there.

A standard problem with sudoer rules for graphical applications is the handling of the access to the X11
display if you need to start programs as another user (e.g. root). (Things may be even worse with Wayland; but I have no experience with it). To keep things simple it is a worthwhile investment to think a bit about the precise nature of your sudo-objective.

In our case we want enforce a user-specific usage of the command remote-viewer. More precisely:

  1. We want to disallow the usage of remote-viewer for most users. And even selected users shall not be able to call or invoke remote-viewer directly and freely.
  2. We want to enforce user-specific arguments to the command “remote-viewer”, if executed by certain selected users.
  3. If possible we do not want to run any remote-tool with root-rights at all.
  4. We want to keep our user-specific firewall rules in place and not to create new ones.
  5. X11-display access shall be possible.

The answer to this challenge is a bit tricky. It first looks like you need to write a separate script (accessible to root) which evaluates UIDs or SUD_UIDs and then calls remote-viewer with appropriate arguments.

But you will then be confronted with problems to access the X11-display of the user issuing the script. In addition rule 3 above forces you to start the required remote-viewer command in the end as a specific user via “sudo -u USER” or “su -c ‘…’ USER”. This in turn forces you to allow “USER” to execute the remote-viewer command anyway according to a specific sudo (!) rule for USER. Therefore, he/she must be able to read and execute the remote-viewer command. But then he/she could execute it outside freely without sudo – and again use any arguments he/she likes. It took me a while to find a way out.

The right approach is to find a rule working for the user in question, first, before you turn to a script as a mediator. On the other side: The user must NOT be allowed to use “remote-viewer” freely – neither by user or group access rights. This seeming contradiction is solved by the following steps on our client-system; we describe the rules below for user “myself”. You must execute most of the commands as root:

  • Step 1: Create a special group, e.g. named “spicegrp”. Do NOT make user “myself” a member of this group!
  • Step 2: Change the ownership and access rights of “/usr/bin/remote-viewer” according to
    • chown root.spicegrp /usr/bin/remote-viewer
    • chmod 750 /usr/bin/remote-viewer
  • Step 3: Check that remote-viewer can no longer be executed by user “myself”.
  • Step 4: Start editing the file “/etc/sudoers” with visudo.
  • Step 5: Add the following lines and turn some existing lines into comments:
     
    ....
    Defaults env_reset
    Defaults env_keep = "LANG LC_ADDRESS LC_CTYPE LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE LC_ATIME LC_ALL LANGUAGE LINGUAS XDG_SESSION_COOKIE"
    
    Defaults:myself env_keep += "DISPLAY"
    
    #Defaults targetpw   # ask for the password of the target user i.e. root
    #ALL   ALL=(ALL) ALL
    
    myself ALL=(myself:spicegrp) /usr/bin/remote-viewer -- spice\://mysrv.anraconc.de?tls-port=20002
    # myself ALL=(myself:spicegrp) NOPASSWD: /usr/bin/remote-viewer -- spice\://mysrv.anraconc.de?tls-port=20002
    # mybro ALL=(mybro:spicegrp) NOPASSWD: /usr/bin/remote-viewer -- spice\://mysrv.anraconc.de?tls-port=20004
    
    

This is all we basically need for the user myself. An extension to
user “mybro” should be clear. See the commented line for mybro.

The sudoer statements – also the commented ones – deserve some short explanation:
We reset the environment, but we keep some language settings for sudoer users. More important: We keep the “DISPLAY” variable of the environment of sudoer user “myself”. Meaning, it will be available when commands are executed with his/her UID. Hereby, we avoid major X11 trouble. The two commented lines in the middle correspond to the the objective that sudoer users should provide their own passwords instead of the root password to execute the commands in the prescribed form.

And then comes some sudo vodoo:

We only define a rule for the user “myself”: We allow him/her to execute the command remote-viewer with his own UID, but with a different group. This gives him access to “/usr/bin/remote-viewer” under “sudo” conditions ( only !). But, in no way else on a shell’s command line, as he/her no longer has access rights to “/usr/bin/remote-viewer” and is no member of “spicegrp”!

The other part of the magic is that the sudoer-mechanism checks the precise form by which the user in question (here: myself) executes the command. It compares the command exactly to the form given in the rule line including the command’s arguments!

myself ALL=(myself:spicegrp) /usr/bin/remote-viewer -- spice\://mysrv.anraconc.de?tls-port=20002

The command and the arguments to it are together handled as one string for comparison!
Thus we have a user “myself” who can only use remote-viewer with “sudo” and he/she is forced to provide a specific argument. And when he issues the command the firewall rules defined in the first part of this post should open doors to the VM as the execution is done with his/her UID!

What will the required sudo command for a successful access to the VM1 (debianx) at TLS-port 20002 on server MySRV look like:

sudo -u myself -g spicegrp remote-viewer — spice://mysrv.anraconc.de?tls-port=20002

You took notice of the argument for the group?

Test for a sudoer user

Let us test our theory (sorry for the German system messages, tried to translate them):

myself@mylap:~> remote-viewer -- spice://mysrv.anraconc.de?tls-port=20002
-bash: /usr/bin/remote-viewer: Keine Berechtigung
myself@mylap:~> # Keine Berechtigung = No access right
myself@mylap:~> # Now with sudo - but wrong port 20004
myself@mylap:~> sudo -u myself -g spicegrp remote-viewer -- spice://mysrv.anraconc.de?tls-port=20004
[sudo] Passwort für myself: 
Leider darf der Benutzer myself »/usr/bin/remote-viewer -- spice://mysrv.anraconc.de?tls-port=20004« als myself:spicegrp auf mylap.anraconc.de nicht ausführen.
myself@mylap:~> # Translation: Sorry, but user myself is not allowed to execute »/usr/bin/remote-viewer -- spice://beta.rux.anraconb.de?tls-port=20004« as myself:spicegrp on mylap.anraconc.de.
myself@mylap:~> # Now with sudo - but the right port 20002
myself@mylap:~> sudo -u myself -g spicegrp remote-viewer -- spice://mysrv.anraconc.de?tls-port=20002

And now we get the familiar dialog to authenticate :

Our firewall obviously has let us through. And – after filling in the VM-specific password (we work without SASL here; see above), we get:

Good!
I leave
it to the reader extend the whole thing to two users and to test all combinations out.

Making things a bit easier for the users

An authorized user has to type a lot of things to make the sudo command work. One thing, you can think about, is to not require a password for the sudo command. (Personally, I would not do this; a password is a last security barrier in case of configuration mistakes. But, in principle it is possible to work without a password in this specific case – after you have checked out and tested all security implications). The entry in the “/etc/sudoers” file then would look like

....
myself ALL=(myself:spicegrp) NOPASSWD: /usr/bin/remote-viewer -- spice\://mysrv.anraconc.de?tls-port=20002
...

Another reduction of typing work comes through a script which readers can read and execute, but not change. The script could make all the relevant decisions for a user. A very simplified version would in my test scenario contain statements like:

#!/bin/bash
host="myserv.anraconc.de"
myself_port="20002"
mybro_port="20004"
Myself_UID="1021"
Mybro_UID="1022"
if  test $SUDO_UID
then
        if test  $UID -ne $SUDO_UID
        then
                echo "error - you are not allowed to run this command as another user"
                exit
        fi
fi
if  test $UID -eq $Myself_UID
then
        echo "Hello Ralph"
        msg="You are entering the Spice console of VM \"debianx\" - happy working"
        echo $msg
        sudo -u "#$UID" -g spicegrp /usr/bin/remote-viewer -- spice://$host?tls-port=$myself_port
elif  test $UID -eq $Mybro_UID
then
        echo "Hello Brother"
        msg4="You are entering the Spice console of VM \"leaptest\" - happy working"
        echo $msg4
        sudo -u "#$UID" -g spicegrp /usr/bin/remote-viewer -- spice://$host?tls-port=$mybro_port
else
        echo "Sorry, you are not allowed to access VMs"
fi

Note that the script would ask for a password before executing the sudo statement enclosed – if you had defined a password request in the sudoer file.
If you absolutely wanted to obfuscate the information contained in this script you could again use the trick with sudo and the special group spicegrp. You would the add lines

myself ALL=(myself:spicegrp) /usr/bin/rviewer
myself ALL=(mybro:spicegrp) /usr/bin/rviewer

to the “/etc/sudoers”-file

Important note:

You must not forget to check the fie permission of the file “/usr/bin/remote-viewer” after SW-updates or upgrades of your system.

I would recommend to start a small scheduled job or a service to check the rights settings frequently.

Conclusion

Remote-viewer connections to VMs cannot be controlled on a user level by the KVM/Qemu server if we just used TLS and SASL. We can set up a VM specific password. But external connections to a VM specific TLS port can only be blocked for external systems and IPs on the server.
However, on Linux client-systems iptables helps us to allow access to the Spice console of a specific VM for a selected user, only. This can be achieved by setting up user specific iptables rules on client-systems. This post has shown you how to create such rules for the OUTPUT chain with fwbuilder. We must set up a systemd service to implement these rules automatically at system (and network) startup.

To restrict users on Linux client systems even more we applied the sudo mechanism in a very specific way: we enforced the usage of certain arguments to the remote-viewer command for specific users. I think the method I discussed is safe; if you find a caveat please send me a mail.

Both strategies can and should be applied in Intranets where we want to provide remote-viewer and the Spice consoles of Qemu VMs as real working instruments.

Open Visual Traceroute, Opensuse Leap 42.1 and sudo – howto – II

In the last article
https://linux-blog.anracom.com/2016/08/16/open-visual-traceroute-opensuse-leap-42-1-and-sudo-howto-i/
of this series I discussed basic steps to get OVT running on an Opensuse Leap 42.1 system. All recipes were based on assigning root rights to the Java-execution of the application’s jar. Root rights were required to perform network packet capturing.

Now, on a multiuser system

  • we want to restrict the access rights to OVT to a group of selected users,
  • we want to improve the startup – such that the selected users do not need to provide the root password.

Note that none of the steps below solves any security problems. It only makes things more convenient.

Change access rights to the OVT files

As in the first article we assume that the OVT-files were placed in a directory “/PATH/TO/OVT” – e.g. “/opt/ovt”.

  • Step 1 – Create a group “ovt” : We create a user group named “ovt” (e.g. with “yast2” or at the commandline with “groupadd”). Then we add the users who later on shall get the privilege to execute “ovtr.sh” – even without giving the root password!
  • Step 2 – Change ownership of “/PATH/TO/OVT” and its subdirectories/files:
    chown -R root.ovt /PATH/TO/OVT
  • Step 3 – Change access rights to “/PATH/TO/OVT” and subdirectories/files:
    chmod -R u+rwx,g+rx-w,o-rwx /PATH/TO/OVT

Changes to /etc/sudoers

We change the file “/etc/sudoers” by using the “visudo” command. (Do NOT edit the “/etc/sudoers”-file directly with an editor – get acquainted with elementary vi-commands if necessary!) I only show options which have an impact on the execution of the “ovtr.sh” file, which starts the OVT Java-program. I do not care about other settings and restrictions in comparison to the standard /etc/sudoers file Opensuse delivers.

  • Step 4 – Add a “Default” definition to the sudoers file:
    Below the last line of existing DEFAULT-definitions in the standard “/etc/sudoers”-file of Opensuse add a line
     
    Defaults!/PATH/TO/OVT/ovtr.sh env_keep += “DISPLAY XAUTHORIZATION XAUTHORITY”
     
    (With the double quotation marks! And, of course, you have to replace /PATH/TO/OVT by the path where you actually installed OVT.) This settings will later allow to keep up the named environment variables (DISPLAY, XAUTHORITY, …) when the command “ovtr.sh” is executed.
  • Step 5 – Add a group related definition to the sudoers file:
    Add a line at the end of your settings for users and groups saying
     
    %ovt ALL = (root) NOPASSWD: /PATH/TO/OVT/ovtr.sh

The last rule guarantees that all members of the group “ovt” can execute

sudo /PATH/TO/OVT/ovtr.sh

without providing the root passsword (or their own password depending on whether Opensuse’s default setting “Defaults targetpw” is kept up in your “sudoers”-file). The first rule preserves the present environment settings of user (member of group “ovt”) regarding DISPLAY and XAUTHORITY, thus enabling the access to the presently open X11-screen.

Simplify the contents of “ovtr.sh”

After the changes described above we only need a small modification to ovtr.sh:

#!/bin/bash
java -Djava.awt.headless=false  -Xmx512m -jar org.leo.
traceroute.jar

 
This is now all that is required!

Let us test it

me@mytux:/opt/ovt> sudo ./ovtr.sh 
12:43:54.768 [main] INFO  org.leo.traceroute.Main - Open Visual Traceroute 1.6.3 
12:43:54.776 [main] INFO  org.leo.traceroute.install.Env - Java run-time version: 1.8.0_101
12:43:54.777 [main] INFO  org.leo.traceroute.install.Env - NASA World Wind Java 2.0 2.0.0
12:43:54.777 [main] INFO  org.leo.traceroute.install.Env - /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
12:43:54.777 [main] INFO  org.leo.traceroute.install.Env - OS:Linux / arch:amd64
Locale en_GB
12:43:57.230 [SwingWorker-pool-1-thread-1] INFO  o.leo.traceroute.core.geo.GeoService - Use geoip db /root/ovtr/GeoLiteCity.dat which is 0 day(s) old
12:43:58.818 [pool-2-thread-1] INFO  o.leo.traceroute.core.ServiceFactory - Try using device eth0 null
12:43:59.056 [pool-2-thread-2] INFO  o.leo.traceroute.core.ServiceFactory - Try using device br0 null
12:43:59.251 [pool-2-thread-3] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr_vmw null
12:44:00.389 [pool-2-thread-8] INFO  o.leo.traceroute.core.ServiceFactory - Try using device vmnet1 null
12:44:01.488 [pool-2-thread-9] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr1 null
12:44:02.589 [pool-2-thread-10] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr2 null
12:44:03.691 [pool-2-thread-11] INFO  o.leo.traceroute.core.ServiceFactory - Try using device vmnet3 null
12:44:04.799 [pool-2-thread-12] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr3 null
12:44:05.908 [pool-2-thread-13] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr4 null
12:44:07.027 [pool-2-thread-14] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr5 null
12:44:08.124 [pool-2-thread-15] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr6 null
12:44:09.231 [pool-2-thread-17] INFO  o.leo.traceroute.core.ServiceFactory - Try using device lo null
12:44:11.467 [AWT-EventQueue-0] INFO  org.leo.traceroute.Main - Startup completed in 16704ms

 
ovt6

Great !

Final convenience steps

We eventually add the path of our OVT installation to the system path variable or tell the users of group “ovt” to add it to their environment.
Another way for a user to simplify the OVT startup would be to put a small script “ovsh” in his home directory with just the lines :

#!/bin/bash
sudo /opt/ovt/ovtr.sh

Then he/she may start OVT by executing “ovsh”. The only difference is that we do not need to type the “sudo”.

Security?

In this article we have made the startup of OVT more convenient by using the /etc/sudoers” file. We also restricted access to OVT to members of a group. Still: Java is executed with root rights. This is something I, personally, do not like because of security reasons. The next article, therefore, concentrates on the possibility to start OVT in a chroot jail.

Open Visual Traceroute, Opensuse Leap 42.1 and sudo – howto – I

IP GeoLocation is useful – not only in the context of professional penetration testing, but also for answering very legitimate questions of both system administrators and normal users. E.g.: Where does my web hosting provider really host my website or all my cloud data? In Germany with relatively strict laws regarding personal data protection, the EU or somewhere else where privacy may not be respected to the full extent I expect?

The German provider 1&1, for example, is very active on the French market, too, but at least very many, if not all French websites seem to be hosted on servers in German computation centers. Good to know for a French customer, both legally and also in case of technical problems.

Also sometimes admins may need to clarify why and where there are latency problems, when a user tries to connect to e.g. web or database servers over the Internet. Another field where IP GeoLocation is very helpful is the analysis of the origin of spam mails from the IP information in mail headers. And, and …

Of course, there are GeoLocation services available on the Internet – but the documentation of result data very often is pretty inconvenient. Now, you could write e.g. a python program for GeoLocation on your own – which is a nice exercise, but you will soon find out that you must have a profound knowledge about networking protocol details. So, from the point of view of a standard Linux user or admin it would be nice to have an easy to use, graphical and open-source solution for IP GeoLocation available on the desktop. Such a program is “Open Visual Traceroute” [OVT] of Leo Lewis.

OVT is Java based; for IP GeoLocation it uses the CityLight-database of the company Mindmax. OVT has a nice graphical interface for the geographical display of the results of tracerouting. It has some simple but helpful log and documentation functionality – and even allows for some “sniffing” inspection into data traffic on network interfaces.

Note that using the latter capability has legal implications – so, always (!) get the explicit allowance from your company owners, if you intend to use this functionality of OVT – e.g. in the course of penetration test. In general: Consider possible legal restrictions of the use of OVT (especially in Germany) – and do it carefully.

This having said: Can we technically use OVT on an Opensuse Leap 42.1 system? The answer is yes, but …. The “BUT” in this case does not refer to functionality, but to general security considerations, which we shall discuss in a later article.

However, let us first have a look at some elementary obstacles which prevent the successful execution of the program on an Opensuse Leap desktop. Starting the application as a normal user leads to a variety of different error messages from the Java side, problems with X11 access and right problems regarding the essential package capturing functionality.

One reason for this behavior is a general problematic aspect of the program: It requires root rights for network analysis capabilities. You think of “sudo” ? Yeah, but …. Actually one can learn a bit about “sudo” when dealing with OVT.

In this article I shall describe 3 simple ways of using OVT on Opensuse Leap 42.1. Note that these approaches are only reasonable for single user machines! Actually, due to its special sniffing capabilities OVT is a program to which only selected users should get access to on a multiuser system. In addition running Java and network package analysis as root leaves us with an uneasy feeling …. But let us first get OVT running at all.

In a second article we restrict the usage of OVT to selected users – and improve the startup of OVT for these users a bit. During the discussion I touch some general “sudo” issues, which may be useful in other contexts. A third article then
argues for using the program in a chroot jail or virtual environment to improve security.

I have posted some of my approaches also in the discussion forum of OVT on Sourceforge (https://sourceforge.net/p/openvisualtrace/discussion/1799338/thread/76f2b798/).

Download / Installation

Installation of OVT is quite simple and basically means to place a folder into some reasonable branch of the file system. A shell script is used to start the program.

The web site http://visualtraceroute.net/ offers the download of different installation packages for different operating systems. For our Opensuse system the most reasonable choice is “Download Universal”. The zip-file behind it expands on our SuSE machine into a folder “OpenVisualTraceRoute1.6.3” with a shell script “ovtr.sh” at the highest level and some required subfolders below. The additional “README.txt” file informs about the present and older versions of OVT – in my case I used version 1.6.3.

On my system I have placed the contents of the mentioned folder into a directory “/opt/ovt/”. But you may take another choice. We abbreviate the full path to this installation directory during the rest of this article by “/PATH/TO/OVT/” and call it “OVT-directory”. The OVT-directory contains a “lib” subdirectory which supplies the required “jar” archives.

In principle the OVT program could be started from the OVT-directory by executing the “ovtr.sh” script there. However, this does not work on OS Leap 42.1 – and results in a variety of error messages.

Requirements for running OVT with full functionality

All steps to overcome the cascade of different errors can better be understood by the regarding the four requirements that must be fulfilled to get access to OVT’s capabilities:

  1. The program must find the “libpcap” library. Actually, in the present version OVT assumes that this library can be found in form of a file “libpcap.so.0.8” in some directory of the PATH environment variable. However, such a file does not exist on Opensuse Leap 42.1!
  2. The program needs to run with root rights (or certain network privileges on a system that support file capabilities). The reason is that it uses libpcap, i.e. network packet capturing on detected network interfaces.
  3. OVT must find and read the shell environment variable DISPLAY – which under some circumstances is not completely trivial.
  4. OVT must get the right to access the X11 display of the non-privileged user who started the X11 desktop.

This list is the result of some trial and error testing plus a closer look at some discussions at Sourceforge.

Make OVT start at all – as a non-privileged user – but with reduced functionality

To get the program running at all for a non-privileged user we must modify the startup script on Opensuse. So, please, change the content of “ovtr.sh” to

#!/bin/bash
#sudo java -Xmx512m -jar org.leo.traceroute.jar
java -Xmx512m -jar org.leo.traceroute.jar

I.e., omit the “sudo” command. The reason for this will become clearer later on. In addition you must the assign execution right to “ovtr.sh”. You then get OVT running in the following form:

me@mytux:/opt/ovt> ./ovtr.sh
13:01:33.276 [main] INFO  org.leo.traceroute.Main - Open Visual Traceroute 1.6.3 
13:01:33.284 [main] INFO  org.leo.traceroute.install.Env - Java run-time version: 1.8.0_91
13:01:33.285 [main] INFO  org.leo.traceroute.
install.Env - NASA World Wind Java 2.0 2.0.0
13:01:33.285 [main] INFO  org.leo.traceroute.install.Env - /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
13:01:33.285 [main] INFO  org.leo.traceroute.install.Env - OS:Linux / arch:amd64
Locale en_GB
13:01:36.063 [SwingWorker-pool-1-thread-1] INFO  o.leo.traceroute.core.geo.GeoService - Use geoip db /home/rmo/ovtr/GeoLiteCity.dat which is 8 day(s) old
13:01:36.772 [SwingWorker-pool-1-thread-1] WARN  o.leo.traceroute.core.ServiceFactory - Cannot find a suitable network device for tracing.
java.lang.UnsatisfiedLinkError: /opt/ovt/native/linux/x64/libjpcap.so: libpcap.so.0.8: Kann die Shared-Object-Datei nicht öffnen: Datei oder Verzeichnis nicht gefunden
        at java.lang.ClassLoader$NativeLibrary.load(Native Method) ~[na:1.8.0_91]
        at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941) ~[na:1.8.0_91]
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1857) ~[na:1.8.0_91]
        at java.lang.Runtime.loadLibrary0(Runtime.java:870) ~[na:1.8.0_91]
        at java.lang.System.loadLibrary(System.java:1122) ~[na:1.8.0_91]
        at jpcap.JpcapCaptor.<clinit>(JpcapCaptor.java:251) ~[jpcap.jar:na]
        at org.leo.traceroute.core.network.JPcapNetworkService.init(JPcapNetworkService.java:90) ~[org.leo.traceroute.jar:na]
        at org.leo.traceroute.core.ServiceFactory.init(ServiceFactory.java:110) [org.leo.traceroute.jar:na]
        at org.leo.traceroute.Main$4.doInBackground(Main.java:115) [org.leo.traceroute.jar:na]
        at org.leo.traceroute.Main$4.doInBackground(Main.java:111) [org.leo.traceroute.jar:na]
        at javax.swing.SwingWorker$1.call(SwingWorker.java:295) [na:1.8.0_91]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_91]
        at javax.swing.SwingWorker.run(SwingWorker.java:334) [na:1.8.0_91]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_91]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_91]
        at java.lang.Thread.run(Thread.java:745) [na:1.8.0_91]
13:01:36.776 [SwingWorker-pool-1-thread-1] WARN  o.l.t.c.n.JNetCapNetworkService - Cannot find a suitable network device for tracing.
java.lang.UnsatisfiedLinkError: /opt/ovt/native/linux/x64/libjnetpcap.so: libpcap.so.0.8: Kann die Shared-Object-Datei nicht öffnen: Datei oder Verzeichnis nicht gefunden
        at java.lang.ClassLoader$NativeLibrary.load(Native Method) ~[na:1.8.0_91]
        at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941) ~[na:1.8.0_91]
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1857) ~[na:1.8.0_91]
        at java.lang.Runtime.loadLibrary0(Runtime.java:870) ~[na:1.8.0_91]
        at java.lang.System.loadLibrary(System.java:1122) ~[na:1.8.0_91]
        at org.jnetpcap.Pcap.<clinit>(Unknown Source) ~[jnetpcap.jar:1.3.0]
        at org.leo.traceroute.core.network.JNetCapNetworkService.init(JNetCapNetworkService.java:71) ~[org.leo.traceroute.jar:na]
        at org.leo.traceroute.core.ServiceFactory.init(ServiceFactory.java:111) [org.leo.traceroute.jar:na]
        at org.leo.traceroute.Main$4.doInBackground(Main.java:115) [org.leo.traceroute.jar:na]
        at org.leo.traceroute.Main$4.doInBackground(Main.java:111) [org.leo.traceroute.jar:na]
        at javax.swing.SwingWorker$1.call(SwingWorker.java:295) [na:1.8.0_91]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_91]
        at javax.swing.SwingWorker.run(SwingWorker.java:334) [na:1.8.0_91]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_91]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_91]
        at java.lang.Thread.run(Thread.java:745) [na:1.8.0_91]
13:01:37.272 [AWT-EventQueue-0] INFO  org.leo.traceroute.Main - Startup completed in 4001ms

 

Despite the many warnings the application opens and displays the following graphical elements, which are quite self-explanatory.
ovt1

However, trying to traceroute some web-address by pressing the orange button results in the displayed error. The reason is that “/usr/sbin” is not included in the PATH variable. Actually, at http://visualtraceroute.net/installation it is recommend to also include

export PATH=”$PATH:/usr/sbin/”; java -Xmx512m -jar -Djava.awt.headless=false org.leo.traceroute.jar

in “ovtr.sh”. Lets do it

#!/bin/bash
export PATH="$PATH:/usr/sbin/"; java -Xmx512m -jar org.leo.traceroute.jar

 
Afterwards, we can run “traceroute” ….
ovt3

However, if we compare our screenshot with illustrations on the site http://visualtraceroute.net/ we detect that our interface lacks a button, e.g. for sniffing. We come back to this a bit later.

Why did we need the “/usr/sbin” in our PATH? Because OVT actually uses the “OS’s traceroute” command as a fallback – if it cannot analyze network packages itself another way. We can conclude this fact from OVT’s “settings”-options (tools button on the right):

ovt2

The option “Use OS traceroute” is set to “Yes” in the combobox – and, under the given conditions, this option cannot be changed.

Give OVT the required libpcap !

Actually, the native Linux traceroute command is a bit limited in its capabilities. Therefore, its results are sometimes not convincing – in very many examples the traceroute analysis is stopped by restrictions in intermediate computation centers. A look at the discussions on OVT at Sourceforge and the version history reveals that OVT, therefore, has its own traceroute program, which is based on capturing and analyzing network protocol packets:

The access to “libpcap” is not only required for sniffing, but also for tracerouting!

The feedback on our terminal from the program start shows 2 times that “libpcap.so.0.8” is missing. In my opinion, for Linux systems, it would have been more reasonable to search for “libpcap.so.1”. But things are easy to remedy. As root we search for “libpcap.so*”, find it under “/usr/lib64” and simply add a new soft link there:

mytux:/usr/lib64 # ln -s /usr/lib64/libpcap.so.1 libpcap.so.0.8

Actually, “libpcap.so.1” itself is linked to the real version presently used on Opensuse Leap 42.1 systems, namely “libpcap.so.1.5.3”:

mytux:/usr/lib64 # ls -lisa | grep libpcap
 793187     0 lrwxrwxrwx   1 root root       23 Aug 12 15:00 libpcap.so.0.8 -> /usr/lib64/libpcap.so.1
 797513     0 lrwxrwxrwx   1 root root       16 Oct 29  2015 libpcap.so.1 -> libpcap.so.1.5.3
 793262   276 -rwxr-xr-x   1 root root   279312 Oct 25  2015 libpcap.so.1.5.3  

 

A new OVT start now results in clean messages without any errors or warnings

me@mytux:/opt/ovt> ./ovtr.sh
15:03:33.154 [main] INFO  org.leo.traceroute.Main 
- Open Visual Traceroute 1.6.3 
15:03:33.166 [main] INFO  org.leo.traceroute.install.Env - Java run-time version: 1.8.0_91
15:03:33.167 [main] INFO  org.leo.traceroute.install.Env - NASA World Wind Java 2.0 2.0.0
15:03:33.167 [main] INFO  org.leo.traceroute.install.Env - /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
15:03:33.168 [main] INFO  org.leo.traceroute.install.Env - OS:Linux / arch:amd64
Locale en_GB
15:03:35.468 [SwingWorker-pool-1-thread-1] INFO  o.leo.traceroute.core.geo.GeoService - Use geoip db /home/rmo/ovtr/GeoLiteCity.dat which is 8 day(s) old
15:03:36.906 [AWT-EventQueue-0] INFO  org.leo.traceroute.Main - Startup completed in 3757ms

 
However, still no sniffing button and no change in the OVT settings – OVT still uses “/usr/sbin/traceroute”.

Does OVT work for user root?

The reason why OVT still does not work as expected is that packet capturing requires root rights or – on systems supporting file capabilities – the setting of some special rights for certain files (we come back to this in the last article of this mini series). Ever tried “wireshark” or “tcpdump”? For these programs – or parts of them – special rights are required, too. To get a step further we now again take the original, unmodified “ovtr.sh” with the sudo command

#!/bin/bash
sudo java -Xmx512m -jar org.leo.traceroute.jar

and try to run it as user “root”. The “sudo” included in the script should do no harm now as we already are root. Or, at least we think so …

So, as an unprivileged user we open a root terminal on our desktop, type in the root password to get shell access or use “su -” in a standard terminal. But, unfortunately, we get a new error:

  
mytux:/opt/ovt # ./ovtr.sh
15:26:39.153 [main] INFO  org.leo.traceroute.Main - Open Visual Traceroute 1.6.3 
15:26:39.161 [main] INFO  org.leo.traceroute.install.Env - Java run-time version: 1.8.0_91
15:26:39.161 [main] INFO  org.leo.traceroute.install.Env - NASA World Wind Java 2.0 2.0.0
15:26:39.162 [main] INFO  org.leo.traceroute.install.Env - /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
15:26:39.162 [main] INFO  org.leo.traceroute.install.Env - OS:Linux / arch:amd64
Locale en_GB
15:26:39.636 [main] ERROR org.leo.traceroute.Main - Uncaught error
java.awt.HeadlessException: 
No X11 DISPLAY variable was set, but this program performed an operation which requires it.
        at java.awt.GraphicsEnvironment.checkHeadless(GraphicsEnvironment.java:204) ~[na:1.8.0_91]
        at java.awt.Window.<init>(Window.java:536) ~[na:1.8.0_91]
        at java.awt.Frame.<init>(Frame.java:420) ~[na:1.8.0_91]
        at javax.swing.JFrame.<init>(JFrame.java:232) ~[na:1.8.0_91]
        at org.leo.traceroute.ui.TraceRouteFrame.<init>(TraceRouteFrame.java:52) ~[org.leo.traceroute.jar:na]
        at org.leo.traceroute.Main.main(Main.java:87) ~[org.leo.traceroute.jar:na]

 
What is the reason for this failure? No X11 DISPLAY variable? An “env” command shows:

mysystem:/opt/ovt # env | grep DISPL
DISPLAY=:0

It took me a bit to see it: The origin of the error actually is the sudo-command in “ovtr.sh” ! Why? The important thing to be aware of is:

“sudo” does not invoke any kind of shell. So, even if the user root had defined special startup scripts for login or execution shells, which specified the export of DISPLAY, such scripts would not be invoked by “sudo” and as a result the DISPLAY variable would be missing. Therefore, Java complains about the X11 DISPLAY variable!

But, as we know, on Opensuse systems a graphical program started from a root terminal/shell
under KDE does know the DISPLAY variable and does start on the unprivileged user’s X11 desktop.
[ Off topic: On OS LEAP 42.1 KDE programs are actually started from the root terminal with ignoring basic KDE settings (font sizes, etc.) of the unprivileged and the root user – which is a mess in general, but it is unimportant here as Java’s AWT is responsible for the graphics, fonts, etc of the OVT interface.]

So, again: What about turning off the “sudo”?

Solution 1: Run OVT as user root – but without “sudo” in the start script ovtr.sh

Actually, any normal user on a standard (!) unmodified Opensuse system would have to know the root password in case he/she wanted to perform a command with “sudo”. The reason for this is a standard entry in the file “/etc/sudoers”:

Defaults        targetpw 

 
Note: On other systems (as Kali) this entry may not be active after installation. But with this entry you may as well start OVT directly from a root shell. “sudo” would ask you for the root password anyway. So, our first working solution will be to start OVT as user root from a root shell, but without the “sudo” in the start script “ovtr.sh”:

#!/bin/bash
java -Xmx512m -jar org.leo.traceroute.jar

And really:

  
mysystem:/opt/ovt # ./ovtr.sh
19:17:23.021 [main] INFO  org.leo.traceroute.Main - Open Visual Traceroute 1.6.3 
19:17:23.029 [main] INFO  org.leo.traceroute.install.Env - Java run-time version: 1.8.0_91
19:17:23.030 [main] INFO  org.leo.traceroute.install.Env - NASA World Wind Java 2.0 2.0.0
19:17:23.030 [main] INFO  org.leo.traceroute.install.Env - /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
19:17:23.030 [main] INFO  org.leo.traceroute.install.Env - OS:Linux / arch:amd64
Locale en_GB
19:17:25.377 [SwingWorker-pool-1-thread-1] INFO  o.leo.traceroute.core.geo.GeoService - Use geoip db /root/ovtr/GeoLiteCity.dat which is 0 day(s) old
19:17:27.110 [pool-2-thread-1] INFO  o.leo.traceroute.core.ServiceFactory - Try using device eth0 null
19:17:27.275 [pool-2-thread-2] INFO  o.leo.traceroute.core.ServiceFactory - Try using device br0 null
19:17:27.446 [pool-2-thread-3] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr_vmw null
19:17:28.509 [pool-2-thread-8] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr1 null
19:17:29.659 [pool-2-thread-9] INFO  o.leo.traceroute.core.ServiceFactory - Try using device vmnet1 null            
19:17:30.682 [pool-2-thread-10] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr2 null           
19:17:31.665 [pool-2-thread-11] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr3 null           
19:17:32.666 [pool-2-thread-12] INFO  o.leo.traceroute.core.ServiceFactory - Try using device vmnet3 null           
19:17:33.683 [pool-2-thread-13] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr4 null           
19:17:34.703 [pool-2-thread-14] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr5 null
19:17:35.688 [pool-2-thread-15] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr6 null
19:17:36.718 [pool-2-thread-17] INFO  o.leo.traceroute.core.ServiceFactory - Try using device lo null
19:17:38.806 [AWT-EventQueue-0] INFO  org.leo.traceroute.Main - Startup completed in 15790ms 

 
Obviously, OVT now detects some network devices on the system. Do not worry, you probably will not see as many network devices as I do. I have a lot of virtual machines installed and attached to a virtual Linux bridge of my test system… 🙂

And, hey, we now see the button for
sniffing – and therefore know that packet capturing is active.

ovt4

And: By some clever intelligence of OVT’s packet analysis we now arrive at the real hosting place of the web address we tracerouted (compare the above image with the first picture where the Linux traceroute was used). Good!

I have experienced the better and more thorough analysis of OVT’s own traceroute routine in other examples, too.

Solution 2: Run OVT with “sudo”-command – but modify it!

The next challenge for me was to make the sudo-command in the standard script work. The required trick is pretty simple: as sudo itself does not invoke a shell by itself, we must explicitly force sudo to do it:

#!/bin/bash
sudo /bin/bash -c ‘export DISPLAY=:0; java -Djava.awt.headless=false -Xmx512m -jar org.leo.traceroute.jar’

Take care of the positions of single quotation marks! When we now start “ovtr.sh” as an unprivileged user, we are prepared to enter the root password. And then – what do you guess?

me@mysystem:/opt/ovt> ./ovtr.sh 
14:55:43.581 [main] INFO  org.leo.traceroute.Main - Open Visual Traceroute 1.6.3 
14:55:43.589 [main] INFO  org.leo.traceroute.install.Env - Java run-time version: 1.8.0_91
14:55:43.590 [main] INFO  org.leo.traceroute.install.Env - NASA World Wind Java 2.0 2.0.0
14:55:43.590 [main] INFO  org.leo.traceroute.install.Env - /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
14:55:43.590 [main] INFO  org.leo.traceroute.install.Env - OS:Linux / arch:amd64
Locale en_GB
Invalid MIT-MAGIC-COOKIE-1 key14:55:43.875 [main] ERROR org.leo.traceroute.Main - Uncaught error
java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11.XToolkit
        at java.lang.Class.forName0(Native Method) ~[na:1.8.0_91]
        at java.lang.Class.forName(Class.java:264) ~[na:1.8.0_91]
        at java.awt.Toolkit$2.run(Toolkit.java:860) ~[na:1.8.0_91]
        at java.awt.Toolkit$2.run(Toolkit.java:855) ~[na:1.8.0_91]
        at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_91]
        at java.awt.Toolkit.getDefaultToolkit(Toolkit.java:854) ~[na:1.8.0_91]
        at java.awt.KeyboardFocusManager.initPeer(KeyboardFocusManager.java:446) ~[na:1.8.0_91]
        at java.awt.KeyboardFocusManager.<init>(KeyboardFocusManager.java:442) ~[na:1.8.0_91]
        at java.awt.DefaultKeyboardFocusManager.<init>(DefaultKeyboardFocusManager.java:65) ~[na:1.8.0_91]
        at java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager(KeyboardFocusManager.java:225) ~[na:1.8.0_91]
        at java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager(KeyboardFocusManager.java:216) ~[na:1.8.0_91]
        at javax.swing.plaf.synth.SynthLookAndFeel.initialize(SynthLookAndFeel.java:616) ~[na:1.8.0_91]
        at javax.swing.plaf.nimbus.NimbusLookAndFeel.initialize(NimbusLookAndFeel.java:105) ~[na:1.8.0_91]
        at javax.swing.UIManager.setLookAndFeel(UIManager.java:538) ~[na:1.8.0_91]
        at javax.swing.UIManager.setLookAndFeel(UIManager.java:583) ~[na:1.8.0_91]
        at org.leo.traceroute.Main.main(Main.java:75) ~[org.leo.traceroute.jar:na]
me@mysystem:/opt/ovt> 

 
What the hack!? However, this problem is simple one. We started Java from a subshell as root. But why should root get access to our X11 display from such an environment? Actually, even root cannot do this without special precautions!

In the case of starting a KDE root terminal as in “solution 1” KDE and pam take care of the X11 access. Also, in case of a ”
su -” command at the prompt this is handled by pam. See the “/etc/pam.d/su” file and look for a line

session optional pam_xauth.so

Let us quickly test our theory about a missing X11 access right by using the “xhost”-command in addition:

me@mysystem:/opt/ovt> xhost +SI:localuser:root
localuser:root being added to access control list
me@mysystem:/opt/ovt> ./ovtr.sh
root's password:
15:40:20.920 [main] INFO  org.leo.traceroute.Main - Open Visual Traceroute 1.6.3 
15:40:20.928 [main] INFO  org.leo.traceroute.install.Env - Java run-time version: 1.8.0_91
15:40:20.929 [main] INFO  org.leo.traceroute.install.Env - NASA World Wind Java 2.0 2.0.0
15:40:20.929 [main] INFO  org.leo.traceroute.install.Env - /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
15:40:20.929 [main] INFO  org.leo.traceroute.install.Env - OS:Linux / arch:amd64
Locale en_GB
15:40:23.313 [SwingWorker-pool-1-thread-1] INFO  o.leo.traceroute.core.geo.GeoService - Use geoip db /root/ovtr/GeoLiteCity.dat which is 0 day(s) old
15:40:24.913 [pool-2-thread-1] INFO  o.leo.traceroute.core.ServiceFactory - Try using device eth0 null
15:40:25.090 [pool-2-thread-2] INFO  o.leo.traceroute.core.ServiceFactory - Try using device br0 null
15:40:25.279 [pool-2-thread-3] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr_vmw null
15:40:26.317 [pool-2-thread-8] INFO  o.leo.traceroute.core.ServiceFactory - Try using device vmnet1 null
15:40:27.339 [pool-2-thread-9] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr1 null
15:40:28.394 [pool-2-thread-10] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr2 null
15:40:29.417 [pool-2-thread-11] INFO  o.leo.traceroute.core.ServiceFactory - Try using device vmnet3 null
15:40:30.445 [pool-2-thread-12] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr3 null
15:40:31.469 [pool-2-thread-13] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr4 null
15:40:32.492 [pool-2-thread-14] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr5 null
15:40:33.512 [pool-2-thread-15] INFO  o.leo.traceroute.core.ServiceFactory - Try using device virbr6 null
15:40:34.534 [pool-2-thread-17] INFO  o.leo.traceroute.core.ServiceFactory - Try using device lo null
15:40:36.711 [AWT-EventQueue-0] INFO  org.leo.traceroute.Main - Startup completed in 15796ms
...
15:40:47.831 [Shutdown] INFO  org.leo.traceroute.install.Env - Preferences saved.
15:40:47.833 [Shutdown] INFO  o.leo.traceroute.ui.TraceRouteFrame - Application exited.
me@mysystem:/opt/ovt> xhost -SI:localuser:root
localuser:root being removed from access control list
me@mysystem:/opt/ovt>

 
Success! But, do not forget to retrieve the access right after having used OVT.

Solution 3: Run OVT with sudo and preserved XAUTHORITY variable

How can we automatize the X11 access a bit? A look at the settings in the simple standard “/etc/sudoers”-file of Opensuse reveals that it should be possible to run the “sudo”-command in our “ovtr.sh” also with the option “-E” (= –preserve-env):

#!/bin/bash
export PATH="$PATH:/usr/sbin/"
env | grep XAUTHO
sudo -E /bin/bash -c 'export DISPLAY=:0; env | grep XAUTHO;  java -Djava.awt.headless=false  -Xmx512m -jar org.leo.traceroute.jar'

 
And really:

 
me@mysystem:/opt/ovt> ./ovtr.sh 
XAUTHORITY=/tmp/xauth-1011-_0
root's password:
SUDO_COMMAND=/bin/bash -c export DISPLAY=:0; env | 
grep XAUTHO;  java -Djava.awt.headless=false  -Xmx512m -jar org.leo.traceroute.jar
XAUTHORITY=/tmp/xauth-1011-_0
19:31:41.610 [main] INFO  org.leo.traceroute.Main - Open Visual Traceroute 1.6.3 
...
....
19:31:45.617 [pool-2-thread-1] INFO  o.leo.traceroute.core.ServiceFactory - Try using device eth0 null
...

 
It works ! I do not recommended to invoke the environment of a standard user this way, but this test just gave us the right idea. The following has the same effect – and is safer as we only use the contents of one variable (XAUTHORITY) of the unprivileged environment:

#!/bin/bash
sudo XAUTHORITY=$XAUTHORITY /bin/bash -c 'export DISPLAY=:0; java -Djava.awt.headless=false  -Xmx512m -jar org.leo.traceroute.jar'

 

Summary

My objective in this post was to present some elementary steps to get OVT running on an Opensuse Leap 42.1 system. We have seen that we need to make the right “libpcap.so” library available and that the “sudo” command in the start script has to be adapted to guarantee both the recognition of the DISPLAY variable and the access to the X11 display. In a first test we have futhermore seen that OVT’s internal traceroute is a bit better than the standard Linux traceroute.

On a multi-user system, however, we need to restrict the access to OVT to a group of trustworthy users. This will be the topic of the next article.

Have some fun with testing out OVT in the meantime!