Skip to content
This repository has been archived by the owner on Oct 31, 2021. It is now read-only.

Commit

Permalink
Improved chroot tests and parameters.
Browse files Browse the repository at this point in the history
Add methods for handling system users.
  • Loading branch information
jrd committed Jan 30, 2013
1 parent 38de339 commit bf11630
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 10 deletions.
26 changes: 23 additions & 3 deletions src/salix-live-installer/chroot.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,35 @@
from execute import *
import os

def execChroot(path, cmd):
def execChroot(path, cmd, shell = False):
"""
Execute cmd in the chroot defined by path.
pathes in cmd should be relative to the new root.
"""
checkRoot()
return execCall(['chroot', path, cmd])
if not path:
raise IOError("You should provide a path to change root.")
elif not os.path.isdir(path):
raise IOError("'{0}' does not exist or is not a directory.".format(path))
chrootCmd = ['chroot', path]
if shell:
chrootCmd.append('sh')
chrootCmd.append('-c')
if type(cmd) == list:
chrootCmd.append(' '.join(cmd))
else:
chrootCmd.append(cmd)
else:
if type(cmd) == list:
chrootCmd.extend(cmd)
else:
chrootCmd.append(cmd)
return execCall(chrootCmd, shell = False)

# Unit test
if __name__ == '__main__':
from assertPlus import *
assertException(Exception, lambda: execChroot("/", "/bin/ls")) # we are not root
assertException(IOError, lambda: execChroot(None, '/bin/ls'))
assertException(IOError, lambda: execChroot('/nonExistant', '/bin/ls'))
assertEquals(0, execChroot('/', '/bin/ls'))
assertEquals(0, execChroot('/', "/bin/ls | grep '.' && echo '** chroot ok **'", shell = True))
135 changes: 128 additions & 7 deletions src/salix-live-installer/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,147 @@
# vim: set et ai sta sw=2 ts=2 tw=0:
"""
Functions to handle users and groups:
- listRegularUsers
-
- listRegularSystemUsers
- createSystemUser
- changePasswordSystemUser
- checkPasswordSystemUser
- deleteSystemUser
"""
from execute import *
from chroot import *
import os
import random
import string
import crypt

def listRegularUsers():
_minUIDForRegularUser = 1000

def listRegularSystemUsers(mountPoint = None):
"""
Returns a sorted list of regular users, i.e. users with id ≥ 1000.
"""
if mountPoint and not os.path.isdir(mountPoint):
raise IOError("'{0}' does not exist or is not a directory.".format(mountPoint))
if mountPoint == None:
mountPoint = ''
ret = []
for line in open('/etc/passwd', 'r').read().splitlines():
for line in open('{0}/etc/passwd'.format(mountPoint), 'rb').read().decode('utf-8').splitlines():
user, _, uid, _ = line.split(':', 3)
if int(uid) >= 1000:
if int(uid) >= _minUIDForRegularUser:
ret.append(user)
return sorted(ret)

def createSystemUser(user, group = '', groups = [
'audio',
'cdrom',
'games',
'floppy',
'fuse',
'lp',
'netdev',
'plugdev',
'power',
'scanner',
'video' ], password = None, shell = '/bin/bash', mountPoint = None):
"""
Create a user 'user' in the system under the 'mountPoint'.
If the 'group' is specified, and is different than __default__, it will be used.
If the 'group' is '' then the default group will be used.
If the 'group' is None then a group of the same name of the user will be created for the new user to be part of.
The newly created user will also be part of the specified 'groups'.
'password' is clear text password that will be used. If not specified, the password will be deactivated for the created user.
See "man useradd" for more information.
"""
checkRoot()
if mountPoint and not os.path.isdir(mountPoint):
raise IOError("'{0}' does not exist or is not a directory.".format(mountPoint))
cmd = ['/usr/sbin/useradd', '-m']
if group == '':
cmd.append('-N')
elif group:
cmd.append('-N')
cmd.append('-g')
cmd.append(group)
else:
cmd.append('-U')
if groups:
cmd.append('-G')
cmd.append(','.join(groups))
if password:
salt = '$1${0}$'.format(''.join(random.Random().sample(string.ascii_letters + string.digits, 8)))
cryptedPwd = crypt.crypt(password, salt)
cmd.append('-p')
cmd.append(cryptedPwd)
if shell:
cmd.append('-s')
cmd.append(shell)
cmd.append(user)
if not mountPoint or mountPoint == '/':
return execCall(cmd, shell = False)
else:
return execChroot(mountPoint, cmd)

def changePasswordSystemUser(user, password, mountPoint = None):
checkRoot()
if mountPoint and not os.path.isdir(mountPoint):
raise IOError("'{0}' does not exist or is not a directory.".format(mountPoint))
if not password:
raise Exception('A password must be provided.')
salt = '$1${0}$'.format(''.join(random.Random().sample(string.ascii_letters + string.digits, 8)))
cryptedPwd = crypt.crypt(password, salt)
cmd = "echo '{0}:{1}' | /usr/sbin/chpasswd -e".format(user, cryptedPwd)
if not mountPoint or mountPoint == '/':
return execCall(cmd, shell = True)
else:
return execChroot(mountPoint, cmd, shell = True)

def checkPasswordSystemUser(user, password, mountPoint = None):
checkRoot()
if mountPoint and not os.path.isdir(mountPoint):
raise IOError("'{0}' does not exist or is not a directory.".format(mountPoint))
if mountPoint == None:
mountPoint = ''
if not password:
raise Exception('A password must be provided.')
users = dict([tuple(line.split(':', 2)[0:2]) for line in open('{0}/etc/shadow'.format(mountPoint), 'r').read().decode('utf-8').splitlines()])
if user in users:
cryptedPwd = users[user]
salt = cryptedPwd[:cryptedPwd.rfind('$') + 1]
return cryptedPwd == crypt.crypt(password, salt)
else:
return False

def deleteSystemUser(user, mountPoint = None):
"""
Remove the specified 'user' from the system under the 'mountPoint'.
"""
checkRoot()
if mountPoint and not os.path.isdir(mountPoint):
raise IOError("'{0}' does not exist or is not a directory.".format(mountPoint))
cmd = ['/usr/sbin/userdel', '-r', user]
if not mountPoint or mountPoint == '/':
return execCall(cmd, shell = False)
else:
return execChroot(mountPoint, cmd)

# Unit test
if __name__ == '__main__':
from assertPlus import *
users = listRegularUsers()
print users
checkRoot()
users = listRegularSystemUsers()
print ' '.join(users)
assertTrue(len(users) > 0)
testUser = '__test__'
assertEquals(0, createSystemUser(testUser, password = 'test'))
assertTrue(testUser in listRegularSystemUsers())
assertTrue(checkPasswordSystemUser(testUser, 'test', mountPoint = '/'))
assertFalse(checkPasswordSystemUser(testUser, 'test2'))
assertEquals(0, deleteSystemUser(testUser))
assertFalse(testUser in listRegularSystemUsers())
assertEquals(0, createSystemUser(testUser, mountPoint = '/./')) # to be different than '/' and to really force the chroot ;-)
assertTrue(testUser in listRegularSystemUsers())
assertEquals(0, changePasswordSystemUser(testUser, 'test'))
assertTrue(checkPasswordSystemUser(testUser, 'test'))
assertFalse(checkPasswordSystemUser(testUser, 'test3'))
assertEquals(0, deleteSystemUser(testUser, mountPoint = '/./'))
assertFalse(testUser in listRegularSystemUsers())

0 comments on commit bf11630

Please sign in to comment.