Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 0 additions & 84 deletions bin/sudoers-add

This file was deleted.

3 changes: 1 addition & 2 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,5 @@ Installation
Optionally after installation
-----------------------------

- Add to sudoers file::
- Install sudoers configuration. For details, see the "Sudoers File" section in :doc:`usage`

sshuttle --sudoers
29 changes: 12 additions & 17 deletions docs/manpage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -262,28 +262,23 @@ 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.
sshuttle prints a configuration to stdout which allows a user to
run sshuttle without a password. This option is INSECURE because,
with some cleverness, it also allows the user to run any command
as root without a password. The output also includes a suggested
method for you to install the configuration.

.. option:: --sudoers-user
Use --sudoers-user to modify the user that it applies to.

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
.. option:: --sudoers-user

Set the file name for the sudoers.d file to be added. Default is
"sshuttle_auto". Only works with --sudoers.
Set the user name or group with %group_name for passwordless
operation. Default is the current user. Set to ALL for all users
(NOT RECOMMENDED: See note about security in --sudoers-no-modify
documentation above). Only works with the --sudoers-no-modify
option.

.. option:: -t <mark>, --tmark=<mark>

Expand Down
49 changes: 14 additions & 35 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,44 +71,23 @@ 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
sshuttle can generate a sudoers.d file for Linux and MacOS. This
allows one or more users to run sshuttle without entering the
local sudo password. **WARNING:** This option is *insecure*
because, with some cleverness, it also allows these users to run any
command (via the --ssh-cmd option) as root without a password.

DO NOT run this command with sudo, it will ask for your sudo password when
it is needed.

A custom 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 helpful if 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::
To print a sudo configuration file and see a suggested way to install it, run::

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
A custom user or group can be set with the
:option:`sshuttle --sudoers-no-modify --sudoers-user {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 option must be used with `--sudoers-no-modify`::

william ALL=NOPASSWD: SSHUTTLE304
sshuttle --sudoers-no-modify --sudoers-user mike
sshuttle --sudoers-no-modify --sudoers-user %sudo
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ def version_scheme(version):
"Programming Language :: Python :: 3.9",
"Topic :: System :: Networking",
],
scripts=['bin/sudoers-add'],
entry_points={
'console_scripts': [
'sshuttle = sshuttle.cmdline:main',
Expand Down
18 changes: 3 additions & 15 deletions sshuttle/cmdline.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import re
import socket
import platform
import sshuttle.helpers as helpers
import sshuttle.client as client
import sshuttle.firewall as firewall
Expand All @@ -14,20 +13,9 @@
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')
return 1

if not opt.sudoers_filename:
log('--sudoers-file must be set or omitted.')
return 1

sudoers(
user_name=opt.sudoers_user,
no_modify=opt.sudoers_no_modify,
file_name=opt.sudoers_filename
)
if opt.sudoers_no_modify:
# sudoers() calls exit() when it completes
sudoers(user_name=opt.sudoers_user)

if opt.daemon:
opt.syslog = 1
Expand Down
24 changes: 6 additions & 18 deletions sshuttle/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,35 +396,23 @@ def convert_arg_line_to_args(self, arg_line):
(internal use only)
"""
)
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.
Prints a sudo configuration to STDOUT which allows a user to
run sshuttle without a password. This option is INSECURE because,
with some cleverness, it also allows the user to run any command
as root without a password. The output also includes a suggested
method for you to install the configuration.
"""
)
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.
Default is the current user. Only works with the --sudoers-no-modify option.
"""
)
parser.add_argument(
Expand Down
75 changes: 25 additions & 50 deletions sshuttle/sudoers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,45 @@
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()}
def build_config(user_name):
template = '''
# WARNING: If you intend to restrict a user to only running the
# sshuttle command as root, THIS CONFIGURATION IS INSECURE.
# When a user can run sshuttle as root (with or without a password),
# they can also run other commands as root because sshuttle itself
# can run a command specified by the user with the --ssh-cmd option.

# INSTRUCTIONS: Add this text to your sudo configuration to run
# sshuttle without needing to enter a sudo password. To use this
# configuration, run 'visudo /etc/sudoers.d/sshuttle_auto' as root and
# paste this text into the editor that it opens. If you want to give
# multiple users these privilages, you may wish to use use different
# filenames for each one (i.e., /etc/sudoers.d/sshuttle_auto_john).

# This configuration was initially generated by the
# 'sshuttle --sudoers-no-modify' command.

# 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
'''

warning_msg = "# WARNING: When you allow a user to run sshuttle as root,\n" \
"# they can then use sshuttle's --ssh-cmd option to run any\n" \
"# command as root.\n"


def build_config(user_name):
content = warning_msg
content += template % {
'ca': command_alias,
'dist_packages': path_to_dist_packages,
content = template % {
# randomize command alias to avoid collisions
'ca': 'SSHUTTLE%(num)s' % {'num': uuid4().hex[-3:].upper()},
'dist_packages': os.path.dirname(os.path.abspath(__file__))[:-9],
'py': sys.executable,
'path': path_to_sshuttle,
'path': sys.argv[0],
'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]
sys.stdout.write(streamdata.decode("ASCII"))
returncode = process.returncode

if returncode:
log('Failed updating sudoers file.')
debug1(streamdata)
exit(returncode)
else:
log('Success, sudoers file update.')
exit(0)


def sudoers(user_name=None, no_modify=None, file_name=None):
def sudoers(user_name=None):
user_name = user_name or getpass.getuser()
content = build_config(user_name)

if no_modify:
sys.stdout.write(content)
exit(0)
else:
sys.stdout.write(warning_msg)
save_config(content, file_name)
sys.stdout.write(content)
exit(0)