Make addhomedir call 'nscd -i passwd'
[mspang/pyceo.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_MESSAGES', '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 key not 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 try:
26     os.setreuid(0, 0)
27     os.setregid(0, 0)
28 except OSError:
29     print "You must be root to use this command."
30     sys.exit(1)
31
32 for pathent in sys.path[:]:
33     if not pathent.find('/usr') == 0:
34         sys.path.remove(pathent)
35
36 from csc.common import conf
37
38 usage = "usage: %s [--quiet] username" % sys.argv[0]
39
40 try:
41     options, arguments = getopt.gnu_getopt(sys.argv[1:], '', ['quiet'])
42 except getopt.GetoptError, e:
43     print usage
44     sys.exit(2)
45
46 if len(arguments) != 1:
47     print usage
48     sys.exit(2)
49
50 quiet = ('--quiet','') in options
51 program = os.path.basename(sys.argv[0])
52 username = arguments[0]
53
54 def fail(message):
55     print >> sys.stderr, "%s: %s" % (program, message)
56     sys.exit(1)
57
58 def debug(message):
59     if not quiet:
60         print message
61
62 def warn(message):
63     print >> sys.stderr, "warning: %s" % message
64
65 try:
66     cfg = conf.read(CONFIG_FILE)
67 except conf.ConfigurationException:
68     fail("could not import configuration from %s" % CONFIG_FILE)
69
70 try:
71     string_fields = ['homedir_regex', 'skeleton_dir', 'quota_prototype']
72     integer_fields = ['homedir_min_uid', 'homedir_mode']
73     conf.check_string_fields(CONFIG_FILE, string_fields, cfg)
74     conf.check_integer_fields(CONFIG_FILE, integer_fields, cfg)
75 except conf.ConfigurationException, e:
76     fail(e)
77
78 if not os.path.isdir(cfg['skeleton_dir']):
79     fail("invalid skeleton dir %s" % cfg['skeleton_dir'])
80
81 try:
82     os.execvp("/usr/sbin/nscd", ("/usr/sbin/nscd", "-i", "passwd"))
83     pwent = pwd.getpwnam(username)
84     uid = pwent.pw_uid
85     gid = pwent.pw_gid
86     homedir = pwent.pw_dir
87 except KeyError:
88     fail("%s: invalid user" % username)
89     
90 if uid < cfg['homedir_min_uid']:
91     fail("uid of account %s is less than homedir_min_uid" % username)
92
93 if not re.match(cfg['homedir_regex'], homedir):
94     fail("homedir of account %s does not match homedir_regex" % username)
95
96 if os.path.exists(homedir):
97     fail("home directory %s exists" % homedir)
98
99 parentdir = os.path.dirname(homedir)
100 if not os.path.isdir(parentdir):
101     fail("parent directory %s does not exist" % parentdir)
102
103 try:
104     debug("creating %s" % homedir)
105     os.mkdir(homedir, cfg['homedir_mode'])
106     os.chown(homedir, uid, gid)
107
108     # copy files from /etc/skel or similar (location is configurable)
109     skel_files = os.listdir(cfg['skeleton_dir'])
110     for filename in skel_files:
111
112         srcpath = cfg['skeleton_dir'] + '/' + filename
113         destpath = homedir + '/' + filename
114         srcstat = os.lstat(srcpath)
115         perm = srcstat.st_mode & 0777
116         
117         if srcstat.st_uid or srcstat.st_gid:
118             warn("skipping %s due to ownership" % srcpath)
119             continue
120         
121         if stat.S_ISLNK(srcstat.st_mode):
122             linkdest = os.readlink(srcpath)
123             debug("linking %s to %s" % (destpath, linkdest))
124             os.symlink(linkdest, destpath)
125             os.lchown(destpath, uid, gid)
126
127         elif stat.S_ISDIR(srcstat.st_mode):
128             debug("adding directory %s" % destpath)
129             os.mkdir(destpath, perm)
130             os.chown(destpath, uid, gid)
131
132         elif stat.S_ISREG(srcstat.st_mode):
133             debug("adding %s" % destpath)
134             src  = open(srcpath)
135             destfd = os.open(destpath, os.O_CREAT|os.O_EXCL|os.O_WRONLY, perm)
136             dest = os.fdopen(destfd, 'w')
137             dest.write(src.read())
138             src.close()
139             dest.close()
140             os.chown(destpath, uid, gid)
141
142         else:
143             warn("file type of %s not supported" % srcpath)
144
145     # set the user's quota
146     setquota = '/usr/sbin/setquota'
147     if os.access(setquota, os.X_OK):
148         protouser = cfg['quota_prototype']
149         debug("copying quotas from %s to %s" % (protouser, username))
150         args = [ setquota, '-u', '-p', protouser, username, '-a' ]
151         result = os.spawnv(os.P_WAIT, setquota, args)
152         if result:
153             warn("setquota returned error code %d" % result)
154     else:
155         warn("cannot find setquota, not setting quota")
156
157     debug("done!")
158
159 except OSError, e:
160     fail(e)