Added "addhomedir", a utility to create home directories for new users.
This commit is contained in:
parent
8577703511
commit
2828ed6997
|
@ -0,0 +1,152 @@
|
||||||
|
#!/usr/bin/python2.4 --
|
||||||
|
"""
|
||||||
|
addhomedir - a script to create home directories for new users
|
||||||
|
|
||||||
|
For the most part, this script mimics the behavior of adduser(8) when
|
||||||
|
creating a home directory. It creates the directory, copies files
|
||||||
|
from /etc/skel, sets permissions, and sets quotas.
|
||||||
|
"""
|
||||||
|
import os, sys, re, pwd, getopt, stat
|
||||||
|
|
||||||
|
CONFIG_FILE = '/etc/csc/accounts.cf'
|
||||||
|
|
||||||
|
safe_environment = ['LOGNAME', 'USERNAME', 'USER', 'HOME', 'TERM', 'LANG'
|
||||||
|
'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MESSAGE', 'LC_MONETARY',
|
||||||
|
'LC_NUMERIC', 'LC_TIME', 'UID', 'GID', 'SSH_CONNECTION', 'SSH_AUTH_SOCK',
|
||||||
|
'SSH_CLIENT']
|
||||||
|
|
||||||
|
for key in os.environ.keys():
|
||||||
|
if not key in safe_environment:
|
||||||
|
del os.environ[key]
|
||||||
|
|
||||||
|
os.environ['PATH'] = '/usr/sbin:/sbin:/usr/bin:/bin'
|
||||||
|
os.umask(0)
|
||||||
|
|
||||||
|
for pathent in sys.path[:]:
|
||||||
|
if not pathent.find('/usr') == 0:
|
||||||
|
sys.path.remove(pathent)
|
||||||
|
|
||||||
|
from csc.common import conf
|
||||||
|
|
||||||
|
usage = "usage: %s [--quiet] username" % sys.argv[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
options, arguments = getopt.gnu_getopt(sys.argv[1:], '', ['quiet'])
|
||||||
|
except getopt.GetoptError, e:
|
||||||
|
print usage
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
if len(arguments) != 1:
|
||||||
|
print usage
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
quiet = ('--quiet','') in options
|
||||||
|
program = os.path.basename(sys.argv[0])
|
||||||
|
username = arguments[0]
|
||||||
|
|
||||||
|
def fail(message):
|
||||||
|
print >> sys.stderr, "%s: %s" % (program, message)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def debug(message):
|
||||||
|
if not quiet:
|
||||||
|
print message
|
||||||
|
|
||||||
|
def warn(message):
|
||||||
|
print >> sys.stderr, "warning: %s" % message
|
||||||
|
|
||||||
|
try:
|
||||||
|
cfg = conf.read(CONFIG_FILE)
|
||||||
|
except conf.ConfigurationException:
|
||||||
|
fail("could not import configuration from %s" % CONFIG_FILE)
|
||||||
|
|
||||||
|
try:
|
||||||
|
string_fields = ['homedir_regex', 'skeleton_dir', 'quota_prototype']
|
||||||
|
integer_fields = ['homedir_min_uid', 'homedir_mode']
|
||||||
|
conf.check_string_fields(CONFIG_FILE, string_fields, cfg)
|
||||||
|
conf.check_integer_fields(CONFIG_FILE, integer_fields, cfg)
|
||||||
|
except conf.ConfigurationException, e:
|
||||||
|
fail(e)
|
||||||
|
|
||||||
|
if not os.path.isdir(cfg['skeleton_dir']):
|
||||||
|
fail("invalid skeleton dir %s" % cfg['skeleton_dir'])
|
||||||
|
|
||||||
|
try:
|
||||||
|
pwent = pwd.getpwnam(username)
|
||||||
|
uid = pwent.pw_uid
|
||||||
|
gid = pwent.pw_gid
|
||||||
|
homedir = pwent.pw_dir
|
||||||
|
except KeyError:
|
||||||
|
fail("%s: invalid user" % username)
|
||||||
|
|
||||||
|
if uid < cfg['homedir_min_uid']:
|
||||||
|
fail("uid of account %s is less than homedir_min_uid" % username)
|
||||||
|
|
||||||
|
if not re.match(cfg['homedir_regex'], homedir):
|
||||||
|
fail("homedir of account %s does not match homedir_regex" % username)
|
||||||
|
|
||||||
|
if os.path.exists(homedir):
|
||||||
|
fail("home directory %s exists" % homedir)
|
||||||
|
|
||||||
|
parentdir = os.path.dirname(homedir)
|
||||||
|
if not os.path.isdir(parentdir):
|
||||||
|
fail("parent directory %s does not exist" % parentdir)
|
||||||
|
|
||||||
|
try:
|
||||||
|
debug("creating %s" % homedir)
|
||||||
|
os.mkdir(homedir, cfg['homedir_mode'])
|
||||||
|
os.chown(homedir, uid, gid)
|
||||||
|
|
||||||
|
# copy files from /etc/skel or similar (location is configurable)
|
||||||
|
skel_files = os.listdir(cfg['skeleton_dir'])
|
||||||
|
for filename in skel_files:
|
||||||
|
|
||||||
|
srcpath = cfg['skeleton_dir'] + '/' + filename
|
||||||
|
destpath = homedir + '/' + filename
|
||||||
|
srcstat = os.lstat(srcpath)
|
||||||
|
perm = srcstat.st_mode & 0777
|
||||||
|
|
||||||
|
if srcstat.st_uid or srcstat.st_gid:
|
||||||
|
warn("skipping %s due to ownership" % srcpath)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if stat.S_ISLNK(srcstat.st_mode):
|
||||||
|
linkdest = os.readlink(srcpath)
|
||||||
|
debug("linking %s to %s" % (destpath, linkdest))
|
||||||
|
os.symlink(linkdest, destpath)
|
||||||
|
os.lchown(destpath, uid, gid)
|
||||||
|
|
||||||
|
elif stat.S_ISDIR(srcstat.st_mode):
|
||||||
|
debug("adding directory %s" % destpath)
|
||||||
|
os.mkdir(destpath, perm)
|
||||||
|
os.chown(destpath, uid, gid)
|
||||||
|
|
||||||
|
elif stat.S_ISREG(srcstat.st_mode):
|
||||||
|
debug("adding %s" % destpath)
|
||||||
|
src = open(srcpath)
|
||||||
|
destfd = os.open(destpath, os.O_CREAT|os.O_EXCL|os.O_WRONLY, perm)
|
||||||
|
dest = os.fdopen(destfd, 'w')
|
||||||
|
dest.write(src.read())
|
||||||
|
src.close()
|
||||||
|
dest.close()
|
||||||
|
os.chown(destpath, uid, gid)
|
||||||
|
|
||||||
|
else:
|
||||||
|
warn("file type of %s not supported" % srcpath)
|
||||||
|
|
||||||
|
# set the user's quota
|
||||||
|
setquota = '/usr/sbin/setquota'
|
||||||
|
if os.access(setquota, os.X_OK):
|
||||||
|
protouser = cfg['quota_prototype']
|
||||||
|
debug("copying quotas from %s to %s" % (protouser, username))
|
||||||
|
args = [ setquota, '-u', '-p', protouser, username, '-a' ]
|
||||||
|
result = os.spawnv(os.P_WAIT, setquota, args)
|
||||||
|
if result:
|
||||||
|
warn("setquota returned error code %d" % result)
|
||||||
|
else:
|
||||||
|
warn("cannot find setquota, not setting quota")
|
||||||
|
|
||||||
|
debug("done!")
|
||||||
|
|
||||||
|
except OSError, e:
|
||||||
|
fail(e)
|
|
@ -8,6 +8,7 @@ Standards-Version: 3.7.2
|
||||||
Package: csc
|
Package: csc
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: python, python2.4, python2.4-ldap, python2.4-pygresql, krb5-user, less, ${shlibs:Depends}
|
Depends: python, python2.4, python2.4-ldap, python2.4-pygresql, krb5-user, less, ${shlibs:Depends}
|
||||||
|
Recommends: quota
|
||||||
Description: Computer Science Club Administrative Utilities
|
Description: Computer Science Club Administrative Utilities
|
||||||
This package contains the CSC Electronic Office
|
This package contains the CSC Electronic Office
|
||||||
and other Computer Science Club administrative
|
and other Computer Science Club administrative
|
||||||
|
|
|
@ -21,6 +21,10 @@ case "$1" in
|
||||||
dpkg-statoverride --add --update $CEO $OFFICE $SUID /usr/bin/ceo
|
dpkg-statoverride --add --update $CEO $OFFICE $SUID /usr/bin/ceo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! dpkg-statoverride --list /usr/bin/addhomedir > /dev/null; then
|
||||||
|
dpkg-statoverride --add --update root $OFFICE $SUID /usr/bin/addhomedir
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -f /etc/csc/ldap.cf ] && ! dpkg-statoverride --list /etc/csc/ldap.cf > /dev/null; then
|
if [ -f /etc/csc/ldap.cf ] && ! dpkg-statoverride --list /etc/csc/ldap.cf > /dev/null; then
|
||||||
dpkg-statoverride --add --update $CEO staff 640 /etc/csc/ldap.cf
|
dpkg-statoverride --add --update $CEO staff 640 /etc/csc/ldap.cf
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -7,6 +7,10 @@ case "$1" in
|
||||||
dpkg-statoverride --remove /usr/bin/ceo || true
|
dpkg-statoverride --remove /usr/bin/ceo || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if dpkg-statoverride --list /usr/bin/addhomedir > /dev/null; then
|
||||||
|
dpkg-statoverride --remove /usr/bin/addhomedir || true
|
||||||
|
fi
|
||||||
|
|
||||||
if dpkg-statoverride --list /etc/csc/ldap.cf > /dev/null; then
|
if dpkg-statoverride --list /etc/csc/ldap.cf > /dev/null; then
|
||||||
dpkg-statoverride --remove /etc/csc/ldap.cf || true
|
dpkg-statoverride --remove /etc/csc/ldap.cf || true
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -7,6 +7,7 @@ build: build-stamp
|
||||||
build-stamp:
|
build-stamp:
|
||||||
mkdir build
|
mkdir build
|
||||||
$(CC) -DFULL_PATH='"/usr/lib/csc/ceo"' -o build/ceo misc/setuid-prog.c
|
$(CC) -DFULL_PATH='"/usr/lib/csc/ceo"' -o build/ceo misc/setuid-prog.c
|
||||||
|
$(CC) -DFULL_PATH='"/usr/lib/csc/addhomedir"' -o build/addhomedir misc/setuid-prog.c
|
||||||
touch build-stamp
|
touch build-stamp
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
@ -27,8 +28,8 @@ install: build
|
||||||
dh_install etc/* etc/csc/
|
dh_install etc/* etc/csc/
|
||||||
dh_install sql/* usr/share/csc/
|
dh_install sql/* usr/share/csc/
|
||||||
|
|
||||||
dh_install bin/ceo usr/lib/csc/
|
dh_install bin/ceo bin/addhomedir usr/lib/csc/
|
||||||
dh_install build/ceo usr/bin/
|
dh_install build/ceo build/addhomedir usr/bin/
|
||||||
|
|
||||||
binary-arch: build install
|
binary-arch: build install
|
||||||
dh_testdir
|
dh_testdir
|
||||||
|
|
|
@ -36,9 +36,17 @@ group_min_id = 10000
|
||||||
group_max_id = 14999
|
group_max_id = 14999
|
||||||
group_desc = "CSC Group"
|
group_desc = "CSC Group"
|
||||||
|
|
||||||
|
### Home Directory Options ###
|
||||||
|
|
||||||
|
skeleton_dir = "/etc/skel"
|
||||||
|
homedir_mode = 0755
|
||||||
|
homedir_min_uid = 10000
|
||||||
|
quota_prototype = "ctdalek"
|
||||||
|
|
||||||
### Validation Tuning ###
|
### Validation Tuning ###
|
||||||
|
|
||||||
username_regex = "^[a-z][-a-z0-9]*$"
|
username_regex = "^[a-z][-a-z0-9]*$"
|
||||||
groupname_regex = "^[a-z][-a-z0-9]*$"
|
groupname_regex = "^[a-z][-a-z0-9]*$"
|
||||||
|
homedir_regex = "^/users/[^\.]+$"
|
||||||
min_password_length = 4
|
min_password_length = 4
|
||||||
shells_file = "/etc/shells"
|
shells_file = "/etc/shells"
|
||||||
|
|
Loading…
Reference in New Issue