Revert "extend plugin password to avoid sudo (use ssh instead calling chpasswd) (#5654)"
This reverts commit 938dd4670b
.
pull/276/merge
parent
40b51b9dc9
commit
6ba41836b6
@ -1,143 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# use passwd-expect to login to host and change password
|
|
||||||
# you need to install expect on the webserver host
|
|
||||||
# i.e. "apt-get install expect" or "yast -i expect"
|
|
||||||
#
|
|
||||||
# you need an writeable .ssh dir in webserver homedir
|
|
||||||
# you can test this by do ssh user@host as webserver
|
|
||||||
#
|
|
||||||
# Parameter:
|
|
||||||
# -ssh use ssh for connetion to host (default)
|
|
||||||
# -host hostname connect to hostname (default localhost)
|
|
||||||
# -timeout # 0 - 99 time in s to wait for response
|
|
||||||
#
|
|
||||||
# all other parameters are passed to passwd-expect, see there.
|
|
||||||
#
|
|
||||||
"""
|
|
||||||
// 2017-02-13: Remarks by Kay Marquardt kay@rrr.de
|
|
||||||
// allowing sudo chpasswd directly opens a security hole!
|
|
||||||
// any script on the webserver can change password for every user, incl. root
|
|
||||||
|
|
||||||
// IMHO the most flexible and secure method for users with interactive shell access is to use ssh with an expect script
|
|
||||||
// I modifed the chpasss driver to provide the old password needed, additionally it pass the script response in case of error.
|
|
||||||
|
|
||||||
// 1. I wrote a wrapper (this script) for expect script provided by this plugin.
|
|
||||||
// 2. move wrapper out of default location to a random place
|
|
||||||
// 3. change permissons of wrapper to root:www 770 to avoid changes by user or webserver
|
|
||||||
// 4. I add some security meassures(see README)
|
|
||||||
// 5. remove sudo rules you may have applied (see README)
|
|
||||||
"""
|
|
||||||
|
|
||||||
# path to ecpect and script name (has to be in the same dir as this script)
|
|
||||||
# "which expect" show the path to expect programm
|
|
||||||
expect = '/usr/bin/expect'
|
|
||||||
script = 'passwd-expect'
|
|
||||||
|
|
||||||
TIMEOUT= 10
|
|
||||||
|
|
||||||
import os, sys, pwd, re
|
|
||||||
import subprocess, signal
|
|
||||||
|
|
||||||
|
|
||||||
# get args for script and extract hostname for us
|
|
||||||
hostname='localhost'
|
|
||||||
scriptargs = ''
|
|
||||||
count=1
|
|
||||||
while(count < len(sys.argv)):
|
|
||||||
# get hostname
|
|
||||||
if sys.argv[count] == '-host':
|
|
||||||
hostname = sys.argv[count+1]
|
|
||||||
# local only args, do not pass
|
|
||||||
try:
|
|
||||||
if sys.argv[count] == '-timeout':
|
|
||||||
count += 2
|
|
||||||
TIMEOUT=int(sys.argv[count-1])
|
|
||||||
continue
|
|
||||||
except ValueError:
|
|
||||||
continue
|
|
||||||
# pass all other args
|
|
||||||
scriptargs += ' ' + sys.argv[count]
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
|
|
||||||
# read username:password\noldpasswd with timeout
|
|
||||||
class TimeoutException(Exception): # Custom exception class
|
|
||||||
pass
|
|
||||||
def timeout_handler(signum, frame): # Custom signal handler
|
|
||||||
raise TimeoutException
|
|
||||||
signal.signal(signal.SIGALRM, timeout_handler)
|
|
||||||
|
|
||||||
# set timeout
|
|
||||||
signal.alarm(TIMEOUT)
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
username, password = sys.stdin.readline().split(':', 1)
|
|
||||||
oldpassw = sys.stdin.readline()
|
|
||||||
except ValueError, e:
|
|
||||||
sys.exit('Malformed input')
|
|
||||||
|
|
||||||
except TimeoutException:
|
|
||||||
sys.exit('Timeout while reading input')
|
|
||||||
else:
|
|
||||||
# clear timeout
|
|
||||||
signal.alarm(0)
|
|
||||||
|
|
||||||
|
|
||||||
# add user to BLACKLIST and/or /etc/ftpusers to disable password change
|
|
||||||
BLACKLIST = [
|
|
||||||
# add blacklisted users here
|
|
||||||
'ftp',
|
|
||||||
]
|
|
||||||
|
|
||||||
# add /etc/ftpusers to BLACKLIST if exist
|
|
||||||
try:
|
|
||||||
with open("/etc/ftpusers", "r") as ins:
|
|
||||||
for line in ins:
|
|
||||||
if line.startswith('#'):
|
|
||||||
continue
|
|
||||||
BLACKLIST.append(line.rstrip('\n'))
|
|
||||||
|
|
||||||
except IOError:
|
|
||||||
# only catch error and continue
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# check if user is blacklisted for password change
|
|
||||||
if username in BLACKLIST:
|
|
||||||
sys.exit('Changing password for user %s is forbidden (user blacklisted)!' %
|
|
||||||
username)
|
|
||||||
|
|
||||||
|
|
||||||
# check if user exit and is allowed to chage password
|
|
||||||
if hostname == 'localhost':
|
|
||||||
try:
|
|
||||||
user = pwd.getpwnam(username)
|
|
||||||
except KeyError, e:
|
|
||||||
sys.exit('No such user: %s' % username)
|
|
||||||
|
|
||||||
if user.pw_uid < 1000:
|
|
||||||
sys.exit('Changing the password for user %s is forbidden (system user)!' %
|
|
||||||
username)
|
|
||||||
|
|
||||||
|
|
||||||
path= os.path.dirname(os.path.realpath(sys.argv[0]))
|
|
||||||
|
|
||||||
# script has to be in same directory
|
|
||||||
if scriptargs == '': scriptargs = ' -ssh -host ' + hostname
|
|
||||||
cmd = expect + ' ' + os.path.dirname(os.path.realpath(sys.argv[0])) + '/' + script + scriptargs + ' -log \|cat'
|
|
||||||
|
|
||||||
# set timeout
|
|
||||||
signal.alarm(TIMEOUT)
|
|
||||||
try:
|
|
||||||
handle = subprocess.Popen( cmd, shell=True, stdin = subprocess.PIPE)
|
|
||||||
handle.communicate('%s\n%s\n%s' % (username, oldpassw.rstrip('\r\n'), password))
|
|
||||||
except TimeoutException:
|
|
||||||
sys.exit('Timeout while changing password (wrong old password)')
|
|
||||||
else:
|
|
||||||
# clear timeout
|
|
||||||
signal.alarm(0)
|
|
||||||
|
|
||||||
|
|
||||||
sys.exit(handle.returncode)
|
|
||||||
|
|
@ -1,95 +1,32 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#
|
|
||||||
# extended wrapper to /user/sbin/chpasswd
|
|
||||||
# - file based blacklist (/etc/ftpusers)
|
|
||||||
# - timeout for reading and writing
|
|
||||||
|
|
||||||
TIMEOUT= 10
|
import sys
|
||||||
|
import pwd
|
||||||
|
import subprocess
|
||||||
|
|
||||||
import os, sys, pwd, re
|
BLACKLIST = (
|
||||||
import subprocess, signal
|
|
||||||
|
|
||||||
|
|
||||||
# get args for script
|
|
||||||
scriptargs = ''
|
|
||||||
count=1
|
|
||||||
while(count < len(sys.argv)):
|
|
||||||
# local only args, do not pass
|
|
||||||
try:
|
|
||||||
if sys.argv[count] == '-timeout':
|
|
||||||
count += 2
|
|
||||||
TIMEOUT=int(sys.argv[count-1])
|
|
||||||
continue
|
|
||||||
except ValueError:
|
|
||||||
continue
|
|
||||||
# pass all other args
|
|
||||||
scriptargs += ' ' + sys.argv[count]
|
|
||||||
count += 1
|
|
||||||
|
|
||||||
# read username:password\noldpasswd with timeout
|
|
||||||
class TimeoutException(Exception): # Custom exception class
|
|
||||||
pass
|
|
||||||
def timeout_handler(signum, frame): # Custom signal handler
|
|
||||||
raise TimeoutException
|
|
||||||
signal.signal(signal.SIGALRM, timeout_handler)
|
|
||||||
|
|
||||||
# set timeout
|
|
||||||
signal.alarm(TIMEOUT)
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
username, password = sys.stdin.readline().split(':', 1)
|
|
||||||
except ValueError, e:
|
|
||||||
sys.exit('Malformed input')
|
|
||||||
|
|
||||||
except TimeoutException:
|
|
||||||
sys.exit('Timeout while reading input')
|
|
||||||
else:
|
|
||||||
# clear timeout
|
|
||||||
signal.alarm(0)
|
|
||||||
|
|
||||||
# add user to BLACKLIST and/or /etc/ftpusers to disable password change
|
|
||||||
BLACKLIST = [
|
|
||||||
# add blacklisted users here
|
# add blacklisted users here
|
||||||
'ftp',
|
#'user1',
|
||||||
]
|
)
|
||||||
|
|
||||||
# add /etc/ftpusers to BLACKLIST if exist
|
|
||||||
try:
|
try:
|
||||||
with open("/etc/ftpusers", "r") as ins:
|
username, password = sys.stdin.readline().split(':', 1)
|
||||||
for line in ins:
|
except ValueError, e:
|
||||||
if line.startswith('#'):
|
sys.exit('Malformed input')
|
||||||
continue
|
|
||||||
BLACKLIST.append(line.rstrip('\n'))
|
|
||||||
|
|
||||||
except IOError:
|
|
||||||
# only catch error and continue
|
|
||||||
pass
|
|
||||||
|
|
||||||
# check if user is blacklisted for password change
|
|
||||||
if username in BLACKLIST:
|
|
||||||
sys.exit('Changing password for user %s is forbidden (user blacklisted)!' %
|
|
||||||
username)
|
|
||||||
|
|
||||||
|
|
||||||
# check if user exit and is allowed to chage password
|
|
||||||
try:
|
try:
|
||||||
user = pwd.getpwnam(username)
|
user = pwd.getpwnam(username)
|
||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
sys.exit('No such user: %s' % username)
|
sys.exit('No such user: %s' % username)
|
||||||
|
|
||||||
if user.pw_uid < 1000:
|
if user.pw_uid < 1000:
|
||||||
sys.exit('Changing the password for user %s is forbidden (system user)!' %
|
sys.exit('Changing the password for user id < 1000 is forbidden')
|
||||||
|
|
||||||
|
if username in BLACKLIST:
|
||||||
|
sys.exit('Changing password for user %s is forbidden (user blacklisted)' %
|
||||||
username)
|
username)
|
||||||
|
|
||||||
# set timeout
|
handle = subprocess.Popen('/usr/sbin/chpasswd', stdin = subprocess.PIPE)
|
||||||
signal.alarm(TIMEOUT)
|
handle.communicate('%s:%s' % (username, password))
|
||||||
try:
|
|
||||||
handle = subprocess.Popen('/usr/sbin/chpasswd', stdin = subprocess.PIPE)
|
|
||||||
handle.communicate('%s:%s' % (username, password))
|
|
||||||
except TimeoutException:
|
|
||||||
sys.exit('Timeout while changing password')
|
|
||||||
else:
|
|
||||||
# clear timeout
|
|
||||||
signal.alarm(0)
|
|
||||||
|
|
||||||
sys.exit(handle.returncode)
|
sys.exit(handle.returncode)
|
||||||
|
Loading…
Reference in New Issue