diff --git a/bin/addhomedir b/bin/addhomedir new file mode 100755 index 0000000..ea5b2b9 --- /dev/null +++ b/bin/addhomedir @@ -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) diff --git a/debian/control b/debian/control index f5ed12b..b72fc4a 100644 --- a/debian/control +++ b/debian/control @@ -8,6 +8,7 @@ Standards-Version: 3.7.2 Package: csc Architecture: any Depends: python, python2.4, python2.4-ldap, python2.4-pygresql, krb5-user, less, ${shlibs:Depends} +Recommends: quota Description: Computer Science Club Administrative Utilities This package contains the CSC Electronic Office and other Computer Science Club administrative diff --git a/debian/postinst b/debian/postinst index 5611620..0a28f7b 100644 --- a/debian/postinst +++ b/debian/postinst @@ -21,6 +21,10 @@ case "$1" in dpkg-statoverride --add --update $CEO $OFFICE $SUID /usr/bin/ceo 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 dpkg-statoverride --add --update $CEO staff 640 /etc/csc/ldap.cf fi diff --git a/debian/postrm b/debian/postrm index 3908d29..b5f7228 100644 --- a/debian/postrm +++ b/debian/postrm @@ -7,6 +7,10 @@ case "$1" in dpkg-statoverride --remove /usr/bin/ceo || true 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 dpkg-statoverride --remove /etc/csc/ldap.cf || true fi diff --git a/debian/rules b/debian/rules index 443ce29..160348a 100755 --- a/debian/rules +++ b/debian/rules @@ -7,6 +7,7 @@ build: build-stamp build-stamp: mkdir build $(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 clean: @@ -27,8 +28,8 @@ install: build dh_install etc/* etc/csc/ dh_install sql/* usr/share/csc/ - dh_install bin/ceo usr/lib/csc/ - dh_install build/ceo usr/bin/ + dh_install bin/ceo bin/addhomedir usr/lib/csc/ + dh_install build/ceo build/addhomedir usr/bin/ binary-arch: build install dh_testdir diff --git a/etc/accounts.cf b/etc/accounts.cf index 553f947..98ff60b 100644 --- a/etc/accounts.cf +++ b/etc/accounts.cf @@ -36,9 +36,17 @@ group_min_id = 10000 group_max_id = 14999 group_desc = "CSC Group" +### Home Directory Options ### + +skeleton_dir = "/etc/skel" +homedir_mode = 0755 +homedir_min_uid = 10000 +quota_prototype = "ctdalek" + ### Validation Tuning ### username_regex = "^[a-z][-a-z0-9]*$" groupname_regex = "^[a-z][-a-z0-9]*$" +homedir_regex = "^/users/[^\.]+$" min_password_length = 4 shells_file = "/etc/shells"