mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
useradd.py: Use contextmanager to prevent leaked filehandles
This also makes some optimizations by not assigning the output of functions to variables when unnecessary, and changes this module to pass arguments to the cmd.run functions as list instead of a string. It also changes some weird behavior for the loginclass functions. There's no reason to return a dictionary that will only have one element, and there is no reason to return a string that is literally just two quotes (i.e. '""') when there is no login class found. An empty string is sufficient, and has the benefit of also evaluating as False as a boolean.
This commit is contained in:
parent
3e902e86b1
commit
f24b979c7c
1 changed files with 116 additions and 143 deletions
|
@ -17,7 +17,7 @@ import copy
|
|||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
from salt.ext.six import string_types
|
||||
from salt.ext import six
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -68,6 +68,25 @@ def _build_gecos(gecos_dict):
|
|||
gecos_dict.get('homephone', ''))
|
||||
|
||||
|
||||
def _update_gecos(name, key, value):
|
||||
'''
|
||||
Common code to change a user's GECOS information
|
||||
'''
|
||||
if not isinstance(value, six.string_types):
|
||||
value = str(value)
|
||||
pre_info = _get_gecos(name)
|
||||
if not pre_info:
|
||||
return False
|
||||
if value == pre_info[key]:
|
||||
return True
|
||||
gecos_data = copy.deepcopy(pre_info)
|
||||
gecos_data[key] = value
|
||||
cmd = ['usermod', '-c', _build_gecos(gecos_data), name]
|
||||
__salt__['cmd.run'](cmd, python_shell=False)
|
||||
post_info = info(name)
|
||||
return _get_gecos(name).get(key) == value
|
||||
|
||||
|
||||
def add(name,
|
||||
uid=None,
|
||||
gid=None,
|
||||
|
@ -99,47 +118,51 @@ def add(name,
|
|||
if gid not in (None, ''):
|
||||
cmd.extend(['-g', str(gid)])
|
||||
elif groups is not None and name in groups:
|
||||
defs_file = '/etc/login.defs'
|
||||
if __grains__['kernel'] != 'OpenBSD':
|
||||
try:
|
||||
for line in salt.utils.fopen('/etc/login.defs'):
|
||||
if 'USERGROUPS_ENAB' not in line[:15]:
|
||||
continue
|
||||
with salt.utils.fopen(defs_file) as fp_:
|
||||
for line in fp_:
|
||||
if 'USERGROUPS_ENAB' not in line[:15]:
|
||||
continue
|
||||
|
||||
if 'yes' in line:
|
||||
cmd.extend([
|
||||
'-g', str(__salt__['file.group_to_gid'](name))
|
||||
])
|
||||
if 'yes' in line:
|
||||
cmd.extend([
|
||||
'-g', str(__salt__['file.group_to_gid'](name))
|
||||
])
|
||||
|
||||
# We found what we wanted, let's break out of the loop
|
||||
break
|
||||
# We found what we wanted, let's break out of the loop
|
||||
break
|
||||
except OSError:
|
||||
log.debug('Error reading /etc/login.defs', exc_info=True)
|
||||
log.debug(
|
||||
'Error reading ' + defs_file,
|
||||
exc_info_on_loglevel=logging.DEBUG
|
||||
)
|
||||
else:
|
||||
usermgmt_file = '/etc/usermgmt.conf'
|
||||
try:
|
||||
for line in salt.utils.fopen('/etc/usermgmt.conf'):
|
||||
if 'group' not in line[:5]:
|
||||
continue
|
||||
with salt.utils.fopen(usermgmt_file) as fp_:
|
||||
for line in fp_:
|
||||
if 'group' not in line[:5]:
|
||||
continue
|
||||
|
||||
for val in line.split(" "):
|
||||
cmd.extend([
|
||||
'-g', str(val[1])
|
||||
])
|
||||
for val in line.split(' '):
|
||||
cmd.extend([
|
||||
'-g', str(val[1])
|
||||
])
|
||||
|
||||
# We found what we wanted, let's break out of the loop
|
||||
break
|
||||
# We found what we wanted, let's break out of the loop
|
||||
break
|
||||
except OSError:
|
||||
# /etc/usermgmt.conf not present: defaults will be used
|
||||
pass
|
||||
|
||||
if isinstance(createhome, bool):
|
||||
if salt.utils.is_true(createhome):
|
||||
if createhome:
|
||||
cmd.append('-m')
|
||||
elif (__grains__['kernel'] != 'NetBSD'
|
||||
and __grains__['kernel'] != 'OpenBSD'):
|
||||
cmd.append('-M')
|
||||
else:
|
||||
log.error('Value passes to ``createhome`` must be a boolean')
|
||||
return False
|
||||
|
||||
if home is not None:
|
||||
cmd.extend(['-d', home])
|
||||
|
@ -220,7 +243,7 @@ def delete(name, remove=False, force=False):
|
|||
if RETCODE_12_ERROR_REGEX.match(ret['stderr']) is not None:
|
||||
# We've hit the bug, let's log it and not fail
|
||||
log.debug(
|
||||
'While the userdel exited with code 12, this is a know bug on '
|
||||
'While the userdel exited with code 12, this is a known bug on '
|
||||
'debian based distributions. See http://goo.gl/HH3FzT'
|
||||
)
|
||||
return True
|
||||
|
@ -263,10 +286,7 @@ def chuid(name, uid):
|
|||
return True
|
||||
cmd = ['usermod', '-u', '{0}'.format(uid), name]
|
||||
__salt__['cmd.run'](cmd, python_shell=False)
|
||||
post_info = info(name)
|
||||
if post_info['uid'] != pre_info['uid']:
|
||||
return post_info['uid'] == uid
|
||||
return False
|
||||
return info(name).get('uid') == uid
|
||||
|
||||
|
||||
def chgid(name, gid):
|
||||
|
@ -284,10 +304,7 @@ def chgid(name, gid):
|
|||
return True
|
||||
cmd = ['usermod', '-g', '{0}'.format(gid), name]
|
||||
__salt__['cmd.run'](cmd, python_shell=False)
|
||||
post_info = info(name)
|
||||
if post_info['gid'] != pre_info['gid']:
|
||||
return post_info['gid'] == gid
|
||||
return False
|
||||
return info(name).get('gid') == gid
|
||||
|
||||
|
||||
def chshell(name, shell):
|
||||
|
@ -305,10 +322,7 @@ def chshell(name, shell):
|
|||
return True
|
||||
cmd = ['usermod', '-s', shell, name]
|
||||
__salt__['cmd.run'](cmd, python_shell=False)
|
||||
post_info = info(name)
|
||||
if post_info['shell'] != pre_info['shell']:
|
||||
return post_info['shell'] == shell
|
||||
return False
|
||||
return info(name).get('shell') == shell
|
||||
|
||||
|
||||
def chhome(name, home, persist=False):
|
||||
|
@ -325,58 +339,64 @@ def chhome(name, home, persist=False):
|
|||
pre_info = info(name)
|
||||
if home == pre_info['home']:
|
||||
return True
|
||||
cmd = 'usermod -d {0} '.format(home)
|
||||
cmd = ['usermod', '-d', '{0}'.format(home)]
|
||||
if persist and __grains__['kernel'] != 'OpenBSD':
|
||||
cmd += ' -m '
|
||||
cmd += name
|
||||
cmd.append('-m')
|
||||
cmd.append(name)
|
||||
__salt__['cmd.run'](cmd, python_shell=False)
|
||||
post_info = info(name)
|
||||
if post_info['home'] != pre_info['home']:
|
||||
return post_info['home'] == home
|
||||
return False
|
||||
return info(name).get('home') == home
|
||||
|
||||
|
||||
def chgroups(name, groups, append=False):
|
||||
'''
|
||||
Change the groups this user belongs to, add append to append the specified
|
||||
groups
|
||||
Change the groups to which this user belongs
|
||||
|
||||
CLI Example:
|
||||
name
|
||||
User to modify
|
||||
|
||||
groups
|
||||
Groups to set for the user
|
||||
|
||||
append : False
|
||||
If ``True``, append the specified group(s). Otherwise, this function
|
||||
will replace the user's groups with the specified group(s).
|
||||
|
||||
CLI Examples:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' user.chgroups foo wheel,root True
|
||||
salt '*' user.chgroups foo wheel,root
|
||||
salt '*' user.chgroups foo wheel,root append=True
|
||||
'''
|
||||
if isinstance(groups, string_types):
|
||||
if isinstance(groups, six.string_types):
|
||||
groups = groups.split(',')
|
||||
ugrps = set(list_groups(name))
|
||||
if ugrps == set(groups):
|
||||
return True
|
||||
cmd = 'usermod '
|
||||
cmd = ['usermod']
|
||||
if __grains__['kernel'] != 'OpenBSD':
|
||||
if append:
|
||||
cmd += '-a '
|
||||
cmd.append('-a')
|
||||
else:
|
||||
if append:
|
||||
cmd += '-G '
|
||||
cmd.append('-G')
|
||||
else:
|
||||
cmd += '-S '
|
||||
cmd.append('-S')
|
||||
if __grains__['kernel'] != 'OpenBSD':
|
||||
cmd += '-G '
|
||||
cmd += '"{0}" {1}'.format(','.join(groups), name)
|
||||
cmdret = __salt__['cmd.run_all'](cmd, python_shell=False)
|
||||
ret = not cmdret['retcode']
|
||||
cmd.append('-G')
|
||||
cmd.extend([','.join(groups), name])
|
||||
result = __salt__['cmd.run_all'](cmd, python_shell=False)
|
||||
# try to fallback on gpasswd to add user to localgroups
|
||||
# for old lib-pamldap support
|
||||
if __grains__['kernel'] != 'OpenBSD':
|
||||
if not ret and ('not found in' in cmdret['stderr']):
|
||||
if result['retcode'] != 0 and 'not found in' in result['stderr']:
|
||||
ret = True
|
||||
for group in groups:
|
||||
cmd = 'gpasswd -a {0} {1}'.format(name, group)
|
||||
cmdret = __salt__['cmd.run_all'](cmd, python_shell=False)
|
||||
if cmdret['retcode']:
|
||||
cmd = ['gpasswd', '-a', '{0}'.format(name), '{1}'.format(group)]
|
||||
if __salt__['cmd.retcode'](cmd, python_shell=False) != 0:
|
||||
ret = False
|
||||
return ret
|
||||
return ret
|
||||
return result['retcode'] == 0
|
||||
|
||||
|
||||
def chfullname(name, fullname):
|
||||
|
@ -389,20 +409,7 @@ def chfullname(name, fullname):
|
|||
|
||||
salt '*' user.chfullname foo "Foo Bar"
|
||||
'''
|
||||
fullname = str(fullname)
|
||||
pre_info = _get_gecos(name)
|
||||
if not pre_info:
|
||||
return False
|
||||
if fullname == pre_info['fullname']:
|
||||
return True
|
||||
gecos_field = copy.deepcopy(pre_info)
|
||||
gecos_field['fullname'] = fullname
|
||||
cmd = ['usermod', '-c', _build_gecos(gecos_field), name]
|
||||
__salt__['cmd.run'](cmd, python_shell=False)
|
||||
post_info = info(name)
|
||||
if post_info['fullname'] != pre_info['fullname']:
|
||||
return post_info['fullname'] == fullname
|
||||
return False
|
||||
return _update_gecos(name, 'fullname', fullname)
|
||||
|
||||
|
||||
def chroomnumber(name, roomnumber):
|
||||
|
@ -415,20 +422,7 @@ def chroomnumber(name, roomnumber):
|
|||
|
||||
salt '*' user.chroomnumber foo 123
|
||||
'''
|
||||
roomnumber = str(roomnumber)
|
||||
pre_info = _get_gecos(name)
|
||||
if not pre_info:
|
||||
return False
|
||||
if roomnumber == pre_info['roomnumber']:
|
||||
return True
|
||||
gecos_field = copy.deepcopy(pre_info)
|
||||
gecos_field['roomnumber'] = roomnumber
|
||||
cmd = ['usermod', '-c', _build_gecos(gecos_field), name]
|
||||
__salt__['cmd.run'](cmd, python_shell=False)
|
||||
post_info = info(name)
|
||||
if post_info['roomnumber'] != pre_info['roomnumber']:
|
||||
return post_info['roomnumber'] == roomnumber
|
||||
return False
|
||||
return _update_gecos(name, 'roomnumber', roomnumber)
|
||||
|
||||
|
||||
def chworkphone(name, workphone):
|
||||
|
@ -439,22 +433,9 @@ def chworkphone(name, workphone):
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' user.chworkphone foo "7735550123"
|
||||
salt '*' user.chworkphone foo 7735550123
|
||||
'''
|
||||
workphone = str(workphone)
|
||||
pre_info = _get_gecos(name)
|
||||
if not pre_info:
|
||||
return False
|
||||
if workphone == pre_info['workphone']:
|
||||
return True
|
||||
gecos_field = copy.deepcopy(pre_info)
|
||||
gecos_field['workphone'] = workphone
|
||||
cmd = ['usermod', '-c', _build_gecos(gecos_field), name]
|
||||
__salt__['cmd.run'](cmd, python_shell=False)
|
||||
post_info = info(name)
|
||||
if post_info['workphone'] != pre_info['workphone']:
|
||||
return post_info['workphone'] == workphone
|
||||
return False
|
||||
return _update_gecos(name, 'workphone', workphone)
|
||||
|
||||
|
||||
def chhomephone(name, homephone):
|
||||
|
@ -465,28 +446,18 @@ def chhomephone(name, homephone):
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' user.chhomephone foo "7735551234"
|
||||
salt '*' user.chhomephone foo 7735551234
|
||||
'''
|
||||
homephone = str(homephone)
|
||||
pre_info = _get_gecos(name)
|
||||
if not pre_info:
|
||||
return False
|
||||
if homephone == pre_info['homephone']:
|
||||
return True
|
||||
gecos_field = copy.deepcopy(pre_info)
|
||||
gecos_field['homephone'] = homephone
|
||||
cmd = ['usermod', '-c', _build_gecos(gecos_field), name]
|
||||
__salt__['cmd.run'](cmd, python_shell=False)
|
||||
post_info = info(name)
|
||||
if post_info['homephone'] != pre_info['homephone']:
|
||||
return post_info['homephone'] == homephone
|
||||
return False
|
||||
return _update_gecos(name, 'homephone', homephone)
|
||||
|
||||
|
||||
def chloginclass(name, loginclass):
|
||||
'''
|
||||
Change the default login class of the user
|
||||
|
||||
.. note::
|
||||
This function only applies to OpenBSD systems.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -495,15 +466,11 @@ def chloginclass(name, loginclass):
|
|||
'''
|
||||
if __grains__['kernel'] != 'OpenBSD':
|
||||
return False
|
||||
pre_info = get_loginclass(name)
|
||||
if loginclass == pre_info['loginclass']:
|
||||
if loginclass == get_loginclass(name):
|
||||
return True
|
||||
cmd = 'usermod -L {0} {1}'.format(loginclass, name)
|
||||
__salt__['cmd.run'](cmd)
|
||||
post_info = get_loginclass(name)
|
||||
if post_info['loginclass'] != pre_info['loginclass']:
|
||||
return post_info['loginclass'] == loginclass
|
||||
return False
|
||||
cmd = ['usermod', '-L', '{0}'.format(loginclass), '{0}'.format(name)]
|
||||
__salt__['cmd.run'](cmd, python_shell=False)
|
||||
return get_loginclass(name) == loginclass
|
||||
|
||||
|
||||
def info(name):
|
||||
|
@ -528,6 +495,9 @@ def get_loginclass(name):
|
|||
'''
|
||||
Get the login class of the user
|
||||
|
||||
.. note::
|
||||
This function only applies to OpenBSD systems.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -536,15 +506,19 @@ def get_loginclass(name):
|
|||
'''
|
||||
if __grains__['kernel'] != 'OpenBSD':
|
||||
return False
|
||||
userinfo = __salt__['cmd.run_stdout']('userinfo {0}'.format(name),
|
||||
output_loglevel='debug')
|
||||
userinfo = __salt__['cmd.run_stdout'](
|
||||
['userinfo', name],
|
||||
python_shell=False)
|
||||
for line in userinfo.splitlines():
|
||||
if line.startswith("class"):
|
||||
loginclass = line.split()
|
||||
if len(loginclass) == 2:
|
||||
return {'loginclass': loginclass[1]}
|
||||
if line.startswith('class'):
|
||||
try:
|
||||
ret = line.split(None, 1)[1]
|
||||
break
|
||||
except ValueError:
|
||||
continue
|
||||
else:
|
||||
return {'loginclass': '""'}
|
||||
ret = ''
|
||||
return ret
|
||||
|
||||
|
||||
def _format_info(data):
|
||||
|
@ -608,13 +582,12 @@ def rename(name, new_name):
|
|||
'''
|
||||
current_info = info(name)
|
||||
if not current_info:
|
||||
raise CommandExecutionError('User {0!r} does not exist'.format(name))
|
||||
raise CommandExecutionError('User \'{0}\' does not exist'.format(name))
|
||||
new_info = info(new_name)
|
||||
if new_info:
|
||||
raise CommandExecutionError('User {0!r} already exists'.format(new_name))
|
||||
cmd = 'usermod -l {0} {1}'.format(new_name, name)
|
||||
__salt__['cmd.run'](cmd)
|
||||
post_info = info(new_name)
|
||||
if post_info['name'] != current_info['name']:
|
||||
return post_info['name'] == new_name
|
||||
return False
|
||||
raise CommandExecutionError(
|
||||
'User \'{0}\' already exists'.format(new_name)
|
||||
)
|
||||
cmd = ['usermod', '-l', '{0}'.format(new_name), '{0}'.format(name)]
|
||||
__salt__['cmd.run'](cmd, python_shell=False)
|
||||
return info(name).get('name') == new_name
|
||||
|
|
Loading…
Add table
Reference in a new issue