Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gopenvpn: init at 0.8 #20859

Closed
wants to merge 3 commits into from
Closed

Conversation

proteansec
Copy link
Contributor

Motivation for this change

Adding gopenvpn package.

Things done
  • Tested using sandboxing
    (nix.useSandbox on NixOS,
    or option build-use-sandbox in nix.conf
    on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • Linux
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nox --run "nox-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Fits CONTRIBUTING.md.

@mention-bot
Copy link

@proteansec, thanks for your PR! By analyzing the history of the files in this pull request, we identified @zimbatm, @zraexy and @edolstra to be potential reviewers.

@proteansec
Copy link
Contributor Author

The package compiles and starts fine, although when trying to connect to VPN, I'm getting the following:

image

In the console the following is displayed:

# pkexec must be setuid root

I've included the pkexec wrapper in the nix package, but we might be able to solve that in the configure.ac file, which contains the --with-pkexec argument.

# Check for PolicyKit pkexec - can be overridden by --with-pkexec
AC_ARG_WITH([pkexec],
        AC_HELP_STRING([--with-pkexec=/path/to/pkexec], [Full path to PolicyKit pkexec]))
if test "x${with_pkexec}" = x; then
   # Auto-detect path if no explicit path was set
   AC_PATH_PROGS([PKEXEC_BINPATH], [pkexec],, [$PATH])
   if test -x "$PKEXEC_BINPATH"; then
      AC_DEFINE_UNQUOTED([USE_PKEXEC], [1], [Use pkexec for privileged operations])
      AC_DEFINE_UNQUOTED([PKEXEC_BINARY_PATH], ["$PKEXEC_BINPATH"], [Path to PolicyKit pkexec])
   else
      AC_MSG_WARN([PolicyKit pkexec was not found])
   fi
else
   if ! test "x${with_pkexec}" = xno; then
      AC_DEFINE_UNQUOTED([USE_PKEXEC], [1], [Use pkexec for privileged operations])
      AC_DEFINE_UNQUOTED([PKEXEC_BINARY_PATH], ["$with_pkexec"], [Path to PolicyKit pkexec])
   else
      AC_MSG_WARN([PolicyKit is not enabled])
   fi
fi

Any further ideas about this problem are welcome in order to be able to come to a fully working package that can be merged to upstream.

#
# Note that this wasn't solved by adding the "-Wformat-nonliteral -Wno-format-security -Wno-error=format-security"
# flags
sed -i -e '/^CFLAGS =/ s/$/ -w/' src/Makefile
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like hardeningDisable = [ "format" ]; should solve this problem

Copy link
Contributor Author

@proteansec proteansec Dec 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thank you for letting me know about this flag.


nativeBuildInputs = [ pkgconfig ];
buildInputs = [ glib gtk2 dbus_glib gmime libnotify libgnome_keyring openssl cyrus_sasl gnonlin sylpheed gob2
gettext intltool libglade polkit pkgconfig autoconf automake expect openvpn makeWrapper ];
Copy link
Member

@Mic92 Mic92 Dec 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use autoreconfHook here in builtInputs instead of autoconf and automake. It probably also make the expect hack and the rest of preConfigure unnecessary

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By adding the autoreconfHook the program does not compile and results in the following error message:

autoreconf: running: aclocal --force -I m4
autoreconf: configure.ac: tracing
autoreconf: configure.ac: not using Libtool
autoreconf: running: /nix/store/rdnli6k94jlgjpyf8ccr9hgdp3pi4p01-autoconf-2.69/bin/autoconf --force
autoreconf: running: /nix/store/rdnli6k94jlgjpyf8ccr9hgdp3pi4p01-autoconf-2.69/bin/autoheader --force
autoreconf: running: automake --add-missing --copy --force-missing
Unescaped left brace in regex is deprecated, passed through in regex; marked by <-- HERE in m/\${ <-- HERE ([^ \t=:+{}]+)}/ at /nix/store/483rb2q3h37xkwr8fjrsk6bz59x5ypg2-automake-1.15/bin/automake line 3936.
automake: warnings are treated as errors
configure.ac:25: warning: The 'AM_PROG_MKDIR_P' macro is deprecated, and its use is discouraged.
configure.ac:25: You should use the Autoconf-provided 'AC_PROG_MKDIR_P' macro instead,
configure.ac:25: and use '$(MKDIR_P)' instead of '$(mkdir_p)'in your Makefile.am files.
configure.ac:25: installing './compile'
configure.ac:25: installing './config.guess'
configure.ac:25: installing './config.sub'
configure.ac:23: installing './install-sh'
configure.ac:23: installing './missing'
src/Makefile.am: installing './depcomp'
autoreconf: automake failed with exit status: 1
builder for ‘/nix/store/1p6iswcb2jg5wn6466nvg9i0ksshmjld-gopenvpn-0.8.drv’ failed with exit code 1

Even with the current code in place, the program compiles only by issuing the following commands one after another:

# autopoint -f
# gettextize -f
# autoreconf -vif 

make install
echo $out
find $out
wrapProgram $out/bin/gopenvpn --set NIX_REDIRECTS ${builtins.concatStringsSep ":" redirects}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move wrapProgram to postInstall and skip all commands above.

@Mic92
Copy link
Member

Mic92 commented Dec 3, 2016

According to this option, should be able to add an entry to configureFlags and remove the REDIRECT workaround.

configureFlags = ["--with-pkexec=${pkexecPath}/bin/pkexec"];

@proteansec
Copy link
Contributor Author

@Mic92 The --with-pkexec works, so the program doesn't display the pkexec must be setuid root anymore. However, I'm still getting the Error launching OpenVPN subprocess, which needs to be invetigated further.

patchPhase = ''
# configure and remote extra "po/Makefile.in" in AC_CONFIG_FILES
sed -i -e 's:AC_CONFIG_FILES(\[pixmaps/Makefile po/Makefile.in:AC_CONFIG_FILES(\[pixmaps/Makefile:g' configure.ac
cat configure.ac | grep CONFIG_FILES
'';

# configure with pkexec to be able to run openvpn as privileged user
configureFlags = ["--with-pkexec=${pkexecPath}/bin/pkexec"];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mixed pkexecPath up with a package variable.
It should be:

configureFlags = ["--with-pkexec=${pkexecPath}/bin/pkexec"];

instead.

@Mic92
Copy link
Member

Mic92 commented Dec 3, 2016

I came up with the following solutions, which compiles fine without hacks:

{ stdenv, fetchFromGitHub,
  pkgconfig, autoreconfHook, automake111x,
  glib, gtk2, gnome2, dbus_glib, gmime, libnotify, libgnome_keyring,
  openssl, cyrus_sasl, gnonlin, sylpheed, gob2, libglade, polkit, openvpn,
  makeWrapper, pkexecPath ? "/var/setuid-wrappers/pkexec" }:

stdenv.mkDerivation rec {
  rev = "2b9285f1ea2d11434b8ee8e10d937b2ea5285b63";
  version = "0.8";
  name = "gopenvpn-${version}";

  src = fetchFromGitHub {
    inherit rev;
    owner = "proteansec";
    repo = "gopenvpn";
    sha256 = "0pkdravr5wm7phdr2rd1rx1ry4dpwkrf0hv7wi99n4ywsl5jqwq8";
  };

  buildInputs = [ glib gtk2 dbus_glib gmime libnotify libgnome_keyring openssl cyrus_sasl gnonlin sylpheed gob2
                  libglade polkit pkgconfig automake111x autoreconfHook openvpn makeWrapper ];

  #  > gopenvpn.c:978:10: error: format not a string literal and no format arguments [-Werror=format-security]
  hardeningDisable = [ "format" ];

  configureFlags = ["--with-pkexec=${pkexecPath}"];

  meta = with stdenv.lib; {
    description = "Graphical front-end for OpenVPN";
    homepage = "http://gopenvpn.sourceforge.net/";
    license = "GPL";
    platforms = platforms.unix;
    maintainers = [ maintainers.eleanor ];
  };
}

However I have no openvpn profile to test it.

@@ -0,0 +1,62 @@
{ stdenv, fetchurl, fetchFromGitHub, pkgconfig, glib, gtk2, gnome2, dbus_glib, gmime, libnotify, libgnome_keyring,
openssl, cyrus_sasl, gnonlin, sylpheed, gob2, gettext, intltool, libglade, polkit, autoconf, automake, expect,
Copy link
Member

@Mic92 Mic92 Dec 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is sylpheed required? I also cannot find any reference to openssl and cyrus_sasl in the code. Please only include packages here, which are actually required.

@proteansec
Copy link
Contributor Author

@Mic92 Thank you for your comments. I've made the appropriate changes, the expect hack is no longer required, plus the unneeded dependencies have been removed.

We yet need to fix the invocation of a program, which results in an error. To be continued...

@Mic92
Copy link
Member

Mic92 commented Dec 3, 2016

you can use sudo nix-shell -p perf-tools --command execsnoop to get more insights, why gopenvpn fails to execute openvpn.

{ stdenv, fetchurl, fetchFromGitHub, pkgconfig, glib, gtk2, gnome2, dbus_glib, gmime, libnotify, libgnome_keyring,
openssl, cyrus_sasl, gnonlin, sylpheed, gob2, gettext, intltool, libglade, polkit, autoconf, automake, expect,
openvpn, makeWrapper, pkexecPath ? "/var/setuid-wrappers/pkexec" }:
{ stdenv, fetchurl, fetchFromGitHub, pkgconfig, autoreconfHook, automake111x, glib, gtk2, gnome2, dbus_glib, gmime,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fetchurl is unused.

@proteansec
Copy link
Contributor Author

I've used execsnoop to snoop on execute events and when connecting to a VPN profile with gopenvpn, I get the following event:

/var/setuid-wrappers/pkexec/bin/pkexec /nix/store/1vzrl6mhp0vv2pr6aplh2y3cg1paglrx-openvpn-2.3.12/bin/openvpn --cd /etc/openvpn --daemon --script-security 2 --management-query-passwords --management-hold --management 127.0.0.1 33218 --config /etc/openvpn/test.ovpn --writepid /var/run/gopenvpn.test.pid

However, the /var/setuid-wrappers/pkexec/bin/pkexec path is not there, but the actual path is /var/setuid-wrappers/pkexec. However even if I manually execute the command (without the /bin/pkexex suffix), I still get that I'm not authorized

# /var/setuid-wrappers/pkexec /nix/store/1vzrl6mhp0vv2pr6aplh2y3cg1paglrx-openvpn-2.3.12/bin/openvpn --cd /etc/openvpn --daemon --script-security 2 --management-query-passwords --management-hold --management 127.0.0.1 33218 --config /etc/openvpn/user.ovpn --writepid /var/run/gopenvpn.user.pid

==== AUTHENTICATING FOR org.freedesktop.policykit.exec ===
Authentication is needed to run `/nix/store/1vzrl6mhp0vv2pr6aplh2y3cg1paglrx-openvpn-2.3.12/bin/openvpn' as the super user
Multiple identities can be used for authentication:
 1.  System administrator (root)
 2.  user
Choose identity to authenticate as (1-2): 1
Password: 
polkit-agent-helper-1: error response to PolicyKit daemon: GDBus.Error:org.freedesktop.PolicyKit1.Error.Failed: No session for cookie
==== AUTHENTICATION FAILED ===
Error executing command as another user: Not authorized

This incident has been reported.

Note that the polkitd is running, but was started with --no-debug, which is why I killed it and run it in debug mode as follows. Note that afterwards I used pkexec gvim to try to start a simple gvim instead of gopenvpn (for testing purposes). However I got the same response about not being authorized as can be seen in the output below.

# su -s /bin/sh polkituser
# /nix/store/7s8axjp1p0wyy3zm1va03i92ahdhhgw9-polkit-0.113/lib/polkit-1/polkitd
Successfully changed to user polkituser
10:39:14.244: Loading rules from directory /etc/polkit-1/rules.d
10:39:14.244: Loading rules from directory /var/run/current-system/sw/share/polkit-1/rules.d
10:39:14.244: Finished loading, compiling and executing 1 rules
Entering main event loop
Connected to the system bus
10:39:14.245: Acquired the name org.freedesktop.PolicyKit1 on the system bus
** (polkitd:20281): WARNING **: Unknown PolkitImplicitAuthorization string 'auth_self_keep_session'
** (polkitd:20281): WARNING **: Error parsing file with URI 'file:///var/run/current-system/sw/share/polkit-1/actions/net.connman.vpn.policy': 16: parse error: parsing aborted
10:39:26.865: Registered Authentication Agent for unix-process:2042:65307574 (system bus name :1.645 [pkexec gvim], object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale en_US.UTF-8)
10:39:32.778: Operator of unix-process:2042:65307574 FAILED to authenticate to gain authorization for action org.freedesktop.policykit.exec for unix-process:2042:65307574 [zsh] (owned by unix-user:user)
10:39:32.781: Unregistered Authentication Agent for unix-process:2042:65307574 (system bus name :1.645, object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale en_US.UTF-8)

I think there are two things we need to solve:

  1. Determine why the path to pkexec is not entirely correct.
  2. Determine why I'm not authorized to perform any pkexec commands.

@Mic92
Copy link
Member

Mic92 commented Dec 4, 2016

Regarding the wrong pkexec path see my configureFlags above. Like I said, I first mixed up ${pkgexecPath} with a package. Does comes gopenvpn with a polkit policy to actually allow gopenvpn to run openvpn as a user? If it does, this have to be added the polkit module probably.

@proteansec
Copy link
Contributor Author

I've fixed the configureFlags accordingly, I have missed that previously. Also, I've enabled the following in my configuration.nix:

security = {
    # polkit
    polkit = {
      enable = true;
      extraConfig = ''
        /* Log authorization checks. */
        polkit.addRule(function(action, subject) {
          polkit.log("user " +  subject.user + " is attempting action " + action.id + " from PID " + subject.pid);
        });

        /* Allow any local user to do anything (dangerous!). */
        polkit.addRule(function(action, subject) {
          if (subject.local) return "yes";
        });
      '';
    };
  };

This is dangerous, since it allows any program to execute any actions, which is why it needs to be modified so that gopenvpn is allowed to execute openvpn process. Gopenvpn comes with the gopenvpn-policy

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
<policyconfig>
        <vendor>OpenVPN</vendor>
        <vendor_url>https://community.openvpn.net/</vendor_url>

        <action id="net.openvpn.gui.gopenvpn">
                <description>Starts an OpenVPN session</description>
                <message>OpenVPN needs permission to start</message>
                <defaults>
                        <allow_any>no</allow_any>
                        <allow_inactive>no</allow_inactive>
                        <allow_active>auth_self_keep</allow_active>
                </defaults>
		<annotate key="org.freedesktop.policykit.exec.path">/usr/sbin/openvpn</annotate>
        </action>
</policyconfig>

Note that after making the above changes GopenVPN works as it should. Therefore, the only thing that remains to do is to actually limit the pkexec policy.

@joachifm
Copy link
Contributor

Is this ready for integration?

@proteansec
Copy link
Contributor Author

Hi, yes it is, a more secure polkit configuration is the following, which must be specified in the configuration.nix. It it possible to add this to the package configuration or at least to the documentation somewhere, so the users installing gopenvpn will know about this and not rely on installing gopenvpn alone.

    polkit = {
      enable = true;
      extraConfig = ''
        polkit.addRule(function(action, subject) {
          if(action.lookup("program").endsWith('/bin/openvpn')) {
            return polkit.Result.YES;
          }
        });
      '';
    };

@Mic92
Copy link
Member

Mic92 commented Jan 11, 2017

The suggested rules make every user root on the system:

$ mkdir ~/bin/
$ cat > ~/bin/gopenvpn <<'EOF'
#!/bin/sh
id
echo "oops!"
EOF
$ chmod +x ~/bin/gopenvpn

Note that also non-root-user can write to /nix/store.
I would suggest to just create a wrapper in /var/setuid-wrappers/ instead.
That way it at least only allows user to start the real gopenvpn.
By the way does gopenvpn allows to use scripts in openvpn profiles?

@joachifm
Copy link
Contributor

@proteansec have you considered @Mic92's suggestions?

@disassembler
Copy link
Member

@proteansec are you still working on this PR or should it be closed out?

@proteansec
Copy link
Contributor Author

Hi, can we use the following polkit configuration. Note that this isn't tested as I don't have time at this instant.

    # polkit
    polkit = {
      enable = true;
      extraConfig = ''
        polkit.addRule(function(action, subject) {
          if(action.lookup("program") == ${pkgs.openvpn}/bin/openvpn) {
            return polkit.Result.YES;
          }
        });
      '';
    };

Currently the polkit configuration needs to be added to the configuration.nix separately. Is there a way to add it automatically when installing gopenvpn.

@c0bw3b
Copy link
Contributor

c0bw3b commented Apr 20, 2019

Staled and unmaintained

@c0bw3b c0bw3b closed this Apr 20, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants