Added "addhomedir", a utility to create home directories for new users.
[public/pyceo-broken.git] / bin / addhomedir
1 #!/usr/bin/python2.4 --
2 """
3 addhomedir - a script to create home directories for new users
4
5 For the most part, this script mimics the behavior of adduser(8) when
6 creating a home directory. It creates the directory, copies files
7 from /etc/skel, sets permissions, and sets quotas.
8 """
9 import os, sys, re, pwd, getopt, stat
10
11 CONFIG_FILE = '/etc/csc/accounts.cf'
12
13 safe_environment = ['LOGNAME', 'USERNAME', 'USER', 'HOME', 'TERM', 'LANG'
14     'LC_ALL', 'LC_COLLATE', 'LC_CTYPE', 'LC_MESSAGE', 'LC_MONETARY',
15     'LC_NUMERIC', 'LC_TIME', 'UID', 'GID', 'SSH_CONNECTION', 'SSH_AUTH_SOCK',
16     'SSH_CLIENT']
17
18 for key in os.environ.keys():
19     if not key in safe_environment:
20         del os.environ[key]
21
22 os.environ['PATH'] = '/usr/sbin:/sbin:/usr/bin:/bin'
23 os.umask(0)
24
25 for pathent in sys.path[:]:
26     if not pathent.find('/usr') == 0:
27         sys.path.remove(pathent)
28
29 from csc.common import conf
30
31 usage = "usage: %s [--quiet] username" % sys.argv[0]
32
33 try:
34     options, arguments = getopt.gnu_getopt(sys.argv[1:], '', ['quiet'])
35 except getopt.GetoptError, e:
36     print usage
37     sys.exit(2)
38
39 if len(arguments) != 1:
40     print usage
41     sys.exit(2)
42
43 quiet = ('--quiet','') in options
44 program = os.path.basename(sys.argv[0])
45 username = arguments[0]
46
47 def fail(message):
48     print >> sys.stderr, "%s: %s" % (program, message)
49     sys.exit(1)
50
51 def debug(message):
52     if not quiet:
53         print message
54
55 def warn(message):
56     print >> sys.stderr, "warning: %s" % message
57
58 try:
59     cfg = conf.read(CONFIG_FILE)
60 except conf.ConfigurationException:
61     fail("could not import configuration from %s" % CONFIG_FILE)
62
63 try:
64     string_fields = ['homedir_regex', 'skeleton_dir', 'quota_prototype']
65     integer_fields = ['homedir_min_uid', 'homedir_mode']
66     conf.check_string_fields(CONFIG_FILE, string_fields, cfg)
67     conf.check_integer_fields(CONFIG_FILE, integer_fields, cfg)
68 except conf.ConfigurationException, e:
69     fail(e)
70
71 if not os.path.isdir(cfg['skeleton_dir']):
72     fail("invalid skeleton dir %s" % cfg['skeleton_dir'])
73
74 try:
75     pwent = pwd.getpwnam(username)
76     uid = pwent.pw_uid
77     gid = pwent.pw_gid
78     homedir = pwent.pw_dir
79 except KeyError:
80     fail("%s: invalid user" % username)
81     
82 if uid < cfg['homedir_min_uid']:
83     fail("uid of account %s is less than homedir_min_uid" % username)
84
85 if not re.match(cfg['homedir_regex'], homedir):
86     fail("homedir of account %s does not match homedir_regex" % username)
87
88 if os.path.exists(homedir):
89     fail("home directory %s exists" % homedir)
90
91 parentdir = os.path.dirname(homedir)
92 if not os.path.isdir(parentdir):
93     fail("parent directory %s does not exist" % parentdir)
94
95 try:
96     debug("creating %s" % homedir)
97     os.mkdir(homedir, cfg['homedir_mode'])
98     os.chown(homedir, uid, gid)
99
100     # copy files from /etc/skel or similar (location is configurable)
101     skel_files = os.listdir(cfg['skeleton_dir'])
102     for filename in skel_files:
103
104         srcpath = cfg['skeleton_dir'] + '/' + filename
105         destpath = homedir + '/' + filename
106         srcstat = os.lstat(srcpath)
107         perm = srcstat.st_mode & 0777
108         
109         if srcstat.st_uid or srcstat.st_gid:
110             warn("skipping %s due to ownership" % srcpath)
111             continue
112         
113         if stat.S_ISLNK(srcstat.st_mode):
114             linkdest = os.readlink(srcpath)
115             debug("linking %s to %s" % (destpath, linkdest))
116             os.symlink(linkdest, destpath)
117             os.lchown(destpath, uid, gid)
118
119         elif stat.S_ISDIR(srcstat.st_mode):
120             debug("adding directory %s" % destpath)
121             os.mkdir(destpath, perm)
122             os.chown(destpath, uid, gid)
123
124         elif stat.S_ISREG(srcstat.st_mode):
125             debug("adding %s" % destpath)
126             src  = open(srcpath)
127             destfd = os.open(destpath, os.O_CREAT|os.O_EXCL|os.O_WRONLY, perm)
128             dest = os.fdopen(destfd, 'w')
129             dest.write(src.read())
130             src.close()
131             dest.close()
132             os.chown(destpath, uid, gid)
133
134         else:
135             warn("file type of %s not supported" % srcpath)
136
137     # set the user's quota
138     setquota = '/usr/sbin/setquota'
139     if os.access(setquota, os.X_OK):
140         protouser = cfg['quota_prototype']
141         debug("copying quotas from %s to %s" % (protouser, username))
142         args = [ setquota, '-u', '-p', protouser, username, '-a' ]
143         result = os.spawnv(os.P_WAIT, setquota, args)
144         if result:
145             warn("setquota returned error code %d" % result)
146     else:
147         warn("cannot find setquota, not setting quota")
148
149     debug("done!")
150
151 except OSError, e:
152     fail(e)