summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Mantly <wmantly@gmail.com>2019-12-12 16:15:31 -0500
committerBrian May <brian@linuxpenguins.xyz>2019-12-13 08:15:31 +1100
commit69d3f7dc64211d3ab91991cc90865dbf9edcba15 (patch)
tree84d44cc4ea82bbc27fcbc70f3ecd0e6f3127d105
parent6ad4473c87511bcafaec3d8d0c69dfcb166b48ed (diff)
Auto sudoers file (#269)
* added sudoers options to command line arguments * added sudoers options to command line arguments * template for sudoers file * Added option for GUI sudo * added support for GUI sudo * script for auto adding sudo file * sudoers auto add works and validates * small change * Clean up for CI * removed code that belongs in another PR * added path for package bins * added sudoers bin * added sudoers-add to setup file * fixed issue with sudoers bash script * auto sudoers now works * added --sudoers-no-modify option * bin now works with ./run * removed debug print * Updated sudoers-add script * Fixed error passing sudoers config to script * more dynamic building of sudoers file * added option to specify sudoers.d file name * fixed indent issue * fixed indent issue * indent issue * clean up * formating * docs * fix for flags * Update usage.rst * removed shell=true * cleared CI errors * cleared CI errors * removed random * cleared linter issue * cleared linter issue * cleared linter issue * updated sudoers-add script * safer temp file * moved bin directory * moved bin directory * removed print * fixed spacing issue * sudoers commands must only containe upper case latters
-rwxr-xr-xbin/sudoers-add76
-rw-r--r--docs/installation.rst10
-rw-r--r--docs/manpage.rst23
-rw-r--r--docs/usage.rst43
-rwxr-xr-xrun1
-rwxr-xr-xsetup.py1
-rw-r--r--sshuttle/cmdline.py17
-rw-r--r--sshuttle/options.py31
-rw-r--r--sshuttle/sudoers.py64
9 files changed, 266 insertions, 0 deletions
diff --git a/bin/sudoers-add b/bin/sudoers-add
new file mode 100755
index 0000000..5bec3d1
--- /dev/null
+++ b/bin/sudoers-add
@@ -0,0 +1,76 @@
+#!/usr/bin/env bash
+# William Mantly <wmantly@gmail.com>
+# MIT License
+# https://github.com/wmantly/sudoers-add
+
+NEWLINE=$'\n'
+CONTENT=""
+ME="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
+
+if [ "$1" == "--help" ] || [ "$1" == "-h" ]; then
+ echo "Usage: $ME [file_path] [sudoers-file-name]"
+ echo "Usage: [content] | $ME sudoers-file-name"
+ echo "This will take a sudoers config validate it and add it to /etc/sudoers.d/{sudoers-file-name}"
+ echo "The config can come from a file, first usage example or piped in second example."
+
+ exit 0
+fi
+
+if [ "$1" == "" ]; then
+ (>&2 echo "This command take at lest one argument. See $ME --help")
+
+ exit 1
+fi
+
+if [ "$2" == "" ]; then
+ FILE_NAME=$1
+ shift
+else
+ FILE_NAME=$2
+fi
+
+if [[ $EUID -ne 0 ]]; then
+ echo "This script must be run as root"
+
+ exit 1
+fi
+
+while read -r line
+do
+ CONTENT+="${line}${NEWLINE}"
+done < "${1:-/dev/stdin}"
+
+if [ "$CONTENT" == "" ]; then
+ (>&2 echo "No config content specified. See $ME --help")
+ exit 1
+fi
+
+if [ "$FILE_NAME" == "" ]; then
+ (>&2 echo "No sudoers file name specified. See $ME --help")
+ exit 1
+fi
+
+# Make a temp file to hold the sudoers config
+umask 077
+TEMP_FILE=$(mktemp)
+echo "$CONTENT" > "$TEMP_FILE"
+
+# Make sure the content is valid
+visudo_STDOUT=$(visudo -c -f "$TEMP_FILE" 2>&1)
+visudo_code=$?
+# The temp file is no longer needed
+rm "$TEMP_FILE"
+
+if [ $visudo_code -eq 0 ]; then
+ echo "$CONTENT" > "/etc/sudoers.d/$FILE_NAME"
+ chmod 0440 "/etc/sudoers.d/$FILE_NAME"
+ echo "The sudoers file /etc/sudoers.d/$FILE_NAME has been successfully created!"
+
+ exit 0
+else
+ echo "Invalid sudoers config!"
+ echo "$visudo_STDOUT"
+
+ exit 1
+fi
+
diff --git a/docs/installation.rst b/docs/installation.rst
index 5a28f6a..2adddf6 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -5,8 +5,18 @@ Installation
pip install sshuttle
+- Debain package manager::
+ sudo apt install sshuttle
+
- Clone::
git clone https://github.com/sshuttle/sshuttle.git
cd sshuttle
./setup.py install
+
+
+Optionally after installation
+-----------------------------
+
+- Add to sudoers file
+ sshuttle --sudoers
diff --git a/docs/manpage.rst b/docs/manpage.rst
index 5d09c25..34516ed 100644
--- a/docs/manpage.rst
+++ b/docs/manpage.rst
@@ -234,6 +234,29 @@ Options
makes it a lot easier to debug and test the :option:`--auto-hosts`
feature.
+.. option:: --sudoers
+
+ sshuttle will auto generate the proper sudoers.d config file and add it.
+ Once this is completed, sshuttle will exit and tell the user if
+ it succeed or not. Do not call this options with sudo, it may generate a
+ incorrect config file.
+
+.. option:: --sudoers-no-modify
+
+ sshuttle will auto generate the proper sudoers.d config and print it to
+ stdout. The option will not modify the system at all.
+
+.. option:: --sudoers-user
+
+ Set the user name or group with %group_name for passwordless operation.
+ Default is the current user.set ALL for all users. Only works with
+ --sudoers or --sudoers-no-modify option.
+
+--option:: --sudoers-filename
+
+ Set the file name for the sudoers.d file to be added. Default is
+ "sshuttle_auto". Only works with --sudoers.
+
.. option:: --version
Print program version.
diff --git a/docs/usage.rst b/docs/usage.rst
index d782a95..d1960c1 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -60,3 +60,46 @@ the data back and forth through ssh.
Fun, right? A poor man's instant VPN, and you don't even have to have
admin access on the server.
+Sudoers File
+------------
+sshuttle can auto-generate the proper sudoers.d file using the current user
+for Linux and OSX. Doing this will allow sshuttle to run without asking for
+the local sudo password and to give users who do not have sudo access
+ability to run sshuttle.
+
+ sshuttle --sudoers
+
+DO NOT run this command with sudo, it will ask for your sudo password when
+it is needed.
+
+A costume user or group can be set with the :
+option:`sshuttle --sudoers --sudoers-username {user_descriptor}` option. Valid
+values for this vary based on how your system is configured. Values such as
+usernames, groups pre-pended with `%` and sudoers user aliases will work. See
+the sudoers manual for more information on valid user specif actions.
+The options must be used with `--sudoers`
+
+ sshuttle --sudoers --sudoers-user mike
+ sshuttle --sudoers --sudoers-user %sudo
+
+The name of the file to be added to sudoers.d can be configured as well. This
+is mostly not necessary but can be useful for giving more than one user
+access to sshuttle. The default is `sshuttle_auto`
+
+ sshuttle --sudoer --sudoers-filename sshuttle_auto_mike
+ sshuttle --sudoer --sudoers-filename sshuttle_auto_tommy
+
+You can also see what configuration will be added to your system without
+modifying anything. This can be helpfull is the auto feature does not work, or
+you want more control. This option also works with `--sudoers-username`.
+`--sudoers-filename` has no effect with this option.
+
+ sshuttle --sudoers-no-modify
+
+This will simply sprint the generated configuration to STDOUT. Example
+
+ 08:40 PM william$ sshuttle --sudoers-no-modify
+
+ Cmnd_Alias SSHUTTLE304 = /usr/bin/env PYTHONPATH=/usr/local/lib/python2.7/dist-packages/sshuttle-0.78.5.dev30+gba5e6b5.d20180909-py2.7.egg /usr/bin/python /usr/local/bin/sshuttle --method auto --firewall
+
+ william ALL=NOPASSWD: SSHUTTLE304
diff --git a/run b/run
index c52932a..c2c1a33 100755
--- a/run
+++ b/run
@@ -1,6 +1,7 @@
#!/usr/bin/env sh
set -e
export PYTHONPATH="$(dirname $0):$PYTHONPATH"
+export PATH="$(dirname $0)/bin:$PATH"
python_best_version() {
if [ -x "$(command -v python3)" ] &&
diff --git a/setup.py b/setup.py
index d5f3c7e..5d71237 100755
--- a/setup.py
+++ b/setup.py
@@ -52,6 +52,7 @@ setup(
"Programming Language :: Python :: 3.5",
"Topic :: System :: Networking",
],
+ scripts=['bin/sudoers-add'],
entry_points={
'console_scripts': [
'sshuttle = sshuttle.cmdline:main',
diff --git a/sshuttle/cmdline.py b/sshuttle/cmdline.py
index 31a57bf..5f1ba10 100644
--- a/sshuttle/cmdline.py
+++ b/sshuttle/cmdline.py
@@ -1,5 +1,6 @@
import re
import socket
+import platform
import sshuttle.helpers as helpers
import sshuttle.client as client
import sshuttle.firewall as firewall
@@ -7,11 +8,27 @@ import sshuttle.hostwatch as hostwatch
import sshuttle.ssyslog as ssyslog
from sshuttle.options import parser, parse_ipport
from sshuttle.helpers import family_ip_tuple, log, Fatal
+from sshuttle.sudoers import sudoers
def main():
opt = parser.parse_args()
+ if opt.sudoers or opt.sudoers_no_modify:
+ if platform.platform().startswith('OpenBSD'):
+ log('Automatic sudoers does not work on BSD')
+ exit(1)
+
+ if not opt.sudoers_filename:
+ log('--sudoers-file must be set or omited.')
+ exit(1)
+
+ sudoers(
+ user_name=opt.sudoers_user,
+ no_modify=opt.sudoers_no_modify,
+ file_name=opt.sudoers_filename
+ )
+
if opt.daemon:
opt.syslog = 1
if opt.wrap:
diff --git a/sshuttle/options.py b/sshuttle/options.py
index 62f3510..79c404b 100644
--- a/sshuttle/options.py
+++ b/sshuttle/options.py
@@ -322,6 +322,37 @@ parser.add_argument(
"""
)
parser.add_argument(
+ "--sudoers",
+ action="store_true",
+ help="""
+ Add sshuttle to the sudoers for this user
+ """
+)
+parser.add_argument(
+ "--sudoers-no-modify",
+ action="store_true",
+ help="""
+ Prints the sudoers config to STDOUT and DOES NOT modify anything.
+ """
+)
+parser.add_argument(
+ "--sudoers-user",
+ default="",
+ help="""
+ Set the user name or group with %%group_name for passwordless operation.
+ Default is the current user.set ALL for all users. Only works with
+ --sudoers or --sudoers-no-modify option.
+ """
+)
+parser.add_argument(
+ "--sudoers-filename",
+ default="sshuttle_auto",
+ help="""
+ Set the file name for the sudoers.d file to be added. Default is
+ "sshuttle_auto". Only works with --sudoers or --sudoers-no-modify option.
+ """
+)
+parser.add_argument(
"--no-sudo-pythonpath",
action="store_false",
dest="sudo_pythonpath",
diff --git a/sshuttle/sudoers.py b/sshuttle/sudoers.py
new file mode 100644
index 0000000..3f01e8e
--- /dev/null
+++ b/sshuttle/sudoers.py
@@ -0,0 +1,64 @@
+import os
+import sys
+import getpass
+from uuid import uuid4
+from subprocess import Popen, PIPE
+from sshuttle.helpers import log, debug1
+from distutils import spawn
+
+path_to_sshuttle = sys.argv[0]
+path_to_dist_packages = os.path.dirname(os.path.abspath(__file__))[:-9]
+
+# randomize command alias to avoid collisions
+command_alias = 'SSHUTTLE%(num)s' % {'num': uuid4().hex[-3:].upper()}
+
+# Template for the sudoers file
+template = '''
+Cmnd_Alias %(ca)s = /usr/bin/env PYTHONPATH=%(dist_packages)s %(py)s %(path)s *
+
+%(user_name)s ALL=NOPASSWD: %(ca)s
+'''
+
+
+def build_config(user_name):
+ content = template % {
+ 'ca': command_alias,
+ 'dist_packages': path_to_dist_packages,
+ 'py': sys.executable,
+ 'path': path_to_sshuttle,
+ 'user_name': user_name,
+ }
+
+ return content
+
+
+def save_config(content, file_name):
+ process = Popen([
+ '/usr/bin/sudo',
+ spawn.find_executable('sudoers-add'),
+ file_name,
+ ], stdout=PIPE, stdin=PIPE)
+
+ process.stdin.write(content.encode())
+
+ streamdata = process.communicate()[0]
+ returncode = process.returncode
+
+ if returncode:
+ log('Failed updating sudoers file.\n')
+ debug1(streamdata)
+ exit(returncode)
+ else:
+ log('Success, sudoers file update.\n')
+ exit(0)
+
+
+def sudoers(user_name=None, no_modify=None, file_name=None):
+ user_name = user_name or getpass.getuser()
+ content = build_config(user_name)
+
+ if no_modify:
+ sys.stdout.write(content)
+ exit(0)
+ else:
+ save_config(content, file_name)