~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/makeuser.py

[Uber-commit of holiday work because I lacked a local copy of the branch.]

 ivle.makeuser: Don't use jailconf.py as a header for the in-jail conf.py;
     generate the whole thing using string formatting operators and include
     the template inline.

 ivle.makeuser.make_conf_py: XXX the inclusion of ivle.conf.jail_base in
     the jail. It is simply there to placate ivle.studpath, and needs
     to go before we can entirely remove the in-jail config.

 ivle-buildjail:
   - Add. Converted from setup.buildjail.
   - Build the jail in __base_build__ and rsync it to __base__ when
     done, rather than operating only in ./jail
   - Rename --rebuildjail/-j to --recreate/-r, as the whole script
     is now for jail rebuilding. Also add a warning to the usage string about
     the large volume likely to be downloaded.
   - Check existence before removing trees.
   - Don't copy jailconf.py over conf.py in the jail. Also make
     sure that we remove conf.pyc.

 setup.configure:
   - Stop generating jailconf.py at all.
   - Add a jail_system_build setting, defaulting to __base_build__ next to
     the existing __base__.
   - Don't use an OptionParser before calling the real function, as that
     adds options dynamically.

 setup.install:
   - Add an option (-R) to avoid writing out svn revision info to
     $PREFIX/share/ivle/revision.txt.
   - Remove jail-copying things.
   - Install all services to the host, rather than just usrmgt-server. We do
     this so we can build the jail from the host without the source tree.
   - Shuffle some things, and don't install phpBB3 twice.
   - Add a --root argument, to take an alternate root directory to install
     into (as given to autotools in $DESTDIR).

 setup.build:
   - Allow running as non-root.
   - Take a --no-compile option to not byte-compile Python files.

 setup.util:
   - Include usrmgt-server in the list of services.
   - Add make_install_path(), a wrapper around os.path.join() that ensures
     the second path is relative.
   - Install ivle-buildjail with the other binaries.

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
# Do not call os.system("chown www-data") - use Python lib
36
36
# and use the web server uid given in conf. (Several places).
37
37
 
38
 
import hashlib
 
38
import md5
39
39
import os
40
40
import stat
41
41
import shutil
74
74
 
75
75
    chown_to_webserver(path)
76
76
 
77
 
def rebuild_svn_config(store, config):
 
77
def rebuild_svn_config(store):
78
78
    """Build the complete SVN configuration file.
79
 
    @param config: An ivle.config.Config object.
80
79
    """
81
80
    users = store.find(ivle.database.User)
82
81
    groups = {}
83
 
    # TODO: Populate groups with per-offering tutors/lecturers/etc.
84
 
    conf_name = config['paths']['svn']['conf']
85
 
    temp_name = conf_name + ".new"
86
 
    f = open(temp_name, "w")
 
82
    for u in users:
 
83
        role = str(u.role)
 
84
        if role not in groups:
 
85
            groups[role] = []
 
86
        groups[role].append(u.login)
 
87
    f = open(ivle.conf.svn_conf + ".new", "w")
87
88
    f.write("# IVLE SVN Repositories Configuration\n")
88
89
    f.write("# Auto-generated on %s\n" % time.asctime())
89
90
    f.write("\n")
99
100
        #f.write("@admin = rw\n")
100
101
        f.write("\n")
101
102
    f.close()
102
 
    os.rename(temp_name, conf_name)
103
 
    chown_to_webserver(conf_name)
 
103
    os.rename(ivle.conf.svn_conf + ".new", ivle.conf.svn_conf)
 
104
    chown_to_webserver(ivle.conf.svn_conf)
104
105
 
105
 
def rebuild_svn_group_config(store, config):
 
106
def rebuild_svn_group_config(store):
106
107
    """Build the complete SVN configuration file for groups
107
 
    @param config: An ivle.config.Config object.
108
108
    """
109
 
    conf_name = config['paths']['svn']['group_conf']
110
 
    temp_name = conf_name + ".new"
111
 
    f = open(temp_name, "w")
 
109
    f = open(ivle.conf.svn_group_conf + ".new", "w")
112
110
    f.write("# IVLE SVN Group Repositories Configuration\n")
113
111
    f.write("# Auto-generated on %s\n" % time.asctime())
114
112
    f.write("\n")
123
121
            f.write("%s = rw\n" % user.login)
124
122
        f.write("\n")
125
123
    f.close()
126
 
    os.rename(temp_name, conf_name)
127
 
    chown_to_webserver(conf_name)
 
124
    os.rename(ivle.conf.svn_group_conf + ".new", ivle.conf.svn_group_conf)
 
125
    chown_to_webserver(ivle.conf.svn_group_conf)
128
126
 
129
 
def make_svn_auth(store, login, config, throw_on_error=True):
 
127
def make_svn_auth(store, login, throw_on_error=True):
130
128
    """Setup svn authentication for the given user.
131
129
       Uses the given DB store object. Does not commit to the db.
132
130
    """
133
 
    # filename is, eg, /var/lib/ivle/svn/ivle.auth
134
 
    filename = config['paths']['svn']['auth_ivle']
135
 
    passwd = hashlib.md5(uuid.uuid4().bytes).hexdigest()
136
 
    if os.path.exists(filename):
 
131
    passwd = md5.new(uuid.uuid4().bytes).digest().encode('hex')
 
132
    if os.path.exists(ivle.conf.svn_auth_ivle):
137
133
        create = ""
138
134
    else:
139
135
        create = "c"
141
137
    user = ivle.database.User.get_by_login(store, login)
142
138
    user.svn_pass = unicode(passwd)
143
139
 
144
 
    res = os.system("htpasswd -%smb %s %s %s" % (create, filename,
 
140
    res = os.system("htpasswd -%smb %s %s %s" % (create,
 
141
                                              ivle.conf.svn_auth_ivle,
145
142
                                              login, passwd))
146
143
    if res != 0 and throw_on_error:
147
144
        raise Exception("Unable to create ivle-auth for %s" % login)
148
145
 
149
146
    # Make sure the file is owned by the web server
150
147
    if create == "c":
151
 
        chown_to_webserver(filename)
 
148
        chown_to_webserver(ivle.conf.svn_auth_ivle)
152
149
 
153
150
    return passwd
154
151
 
181
178
    return (to_add, to_remove)
182
179
 
183
180
 
184
 
def make_jail(user, config, force=True):
 
181
def make_jail(user, force=True):
185
182
    """Creates a new user's jail space, in the jail directory as configured in
186
183
    conf.py.
187
184
 
200
197
        raise Exception("Must run make_jail as root")
201
198
    
202
199
    # tempdir is for putting backup homes in
203
 
    jail_src_base = config['paths']['jails']['src']
204
 
    tempdir = os.path.join(jail_src_base, '__temp__')
 
200
    tempdir = os.path.join(ivle.conf.jail_base, '__temp__')
205
201
    if not os.path.exists(tempdir):
206
202
        os.makedirs(tempdir)
207
203
    elif not os.path.isdir(tempdir):
208
204
        os.unlink(tempdir)
209
205
        os.mkdir(tempdir)
210
 
    userdir = os.path.join(jail_src_base, user.login)
 
206
    userdir = os.path.join(ivle.conf.jail_src_base, user.login)
211
207
    homedir = os.path.join(userdir, 'home')
212
208
    userhomedir = os.path.join(homedir, user.login)   # Return value
213
209
 
221
217
        warnings.simplefilter('ignore')
222
218
        homebackup = os.tempnam(tempdir)
223
219
        warnings.resetwarnings()
224
 
        # Back up the /home directory, delete the entire jail, recreate the
225
 
        # jail directory tree, then copy the /home back
226
 
        # NOTE that shutil.move changed in Python 2.6, it now moves a
227
 
        # directory INTO the target (like `mv`), which it didn't use to do.
228
 
        # This code works regardless.
 
220
        # Note: shutil.move does not behave like "mv" - it does not put a file
 
221
        # into a directory if it already exists, just fails. Therefore it is
 
222
        # not susceptible to tmpnam symlink attack.
229
223
        shutil.move(homedir, homebackup)
230
224
        shutil.rmtree(userdir)
231
 
        os.makedirs(userdir)
 
225
        os.makedirs(homedir)
232
226
        shutil.move(homebackup, homedir)
233
227
        # Change the ownership of all the files to the right unixid
234
228
        logging.debug("chown %s's home directory files to uid %d"
235
229
            %(user.login, user.unixid))
236
 
        os.spawnvp(os.P_WAIT, 'chown', ['chown', '-R', '%d:%d' % (user.unixid,
237
 
                                        user.unixid), userhomedir])
 
230
        os.chown(userhomedir, user.unixid, user.unixid)
 
231
        for root, dirs, files in os.walk(userhomedir):
 
232
            for fsobj in dirs + files:
 
233
                os.chown(os.path.join(root, fsobj), user.unixid, user.unixid)
238
234
    else:
239
235
        # No user jail exists
240
236
        # Set up the user's home directory
244
240
        # Chmod to rwxr-xr-x (755)
245
241
        os.chmod(userhomedir, 0755)
246
242
 
247
 
    make_ivle_conf(user.login, userdir, user.svn_pass, config)
248
 
    make_etc_passwd(user.login, userdir, config['paths']['jails']['template'],
249
 
                    user.unixid)
 
243
    make_conf_py(user.login, userdir, user.svn_pass)
 
244
    make_etc_passwd(user.login, userdir, ivle.conf.jail_system, user.unixid)
250
245
 
251
246
    return userhomedir
252
247
 
253
 
def make_ivle_conf(username, user_jail_dir, svn_pass, sys_config):
 
248
def make_conf_py(username, user_jail_dir, svn_pass):
254
249
    """
255
250
    Creates (overwriting any existing file, and creating directories) a
256
 
    file /etc/ivle/ivle.conf in a given user's jail.
257
 
    @param username: Username.
258
 
    @param user_jail_dir: User's jail dir, ie. ivle.conf.jail_base + username
259
 
    @param svn_pass: User's SVN password.
260
 
    @param sys_config: An ivle.config.Config object (the system-wide config).
 
251
    file ${python_site_packages}/ivle/conf/conf.py in a given user's jail.
 
252
    username: Username.
 
253
    user_jail_dir: User's jail dir, ie. ivle.conf.jail_base + username
 
254
    svn_pass: User's SVN password.
261
255
    """
262
 
    conf_path = os.path.join(user_jail_dir, "etc/ivle/ivle.conf")
 
256
    conf_path = os.path.join(user_jail_dir,
 
257
            ivle.conf.python_site_packages[1:], "ivle/conf/conf.py")
263
258
    os.makedirs(os.path.dirname(conf_path))
264
259
 
265
260
    # In the "in-jail" version of conf, we don't need MOST of the details
266
261
    # (it would be a security risk to have them here).
267
 
    # So we just write root_dir.
268
 
    conf_obj = ivle.config.Config(blank=True)
269
 
    conf_obj.filename = conf_path
270
 
    conf_obj['urls']['root'] = sys_config['urls']['root']
271
 
    conf_obj['urls']['public_host'] = sys_config['urls']['public_host']
272
 
    conf_obj['urls']['svn_addr'] = sys_config['urls']['svn_addr']
273
 
    conf_obj['user_info']['login'] = username
274
 
    conf_obj['user_info']['svn_pass'] = svn_pass
275
 
    conf_obj.write()
 
262
    # So we just write root_dir, and jail_base is "/".
 
263
    # (jail_base being "/" means "jail-relative" paths are relative to "/"
 
264
    # when inside the jail.)
 
265
 
 
266
    # XXX: jail_base is wrong and shouldn't be here. Unfortunately, jail code
 
267
    #      uses ivle.studpath.url_to_{local,jailpaths}, both of which use
 
268
    #      jail_base. Note that they don't use the bits of the return value
 
269
    #      that depend on jail_base, so it can be any string.
 
270
    conf_file = open(conf_path, "w")
 
271
    conf_file.write("""# IVLE jail configuration
 
272
 
 
273
# In URL space, where in the site is IVLE located. (All URLs will be prefixed
 
274
# with this).
 
275
# eg. "/" or "/ivle".
 
276
root_dir = %(root_dir)r
 
277
 
 
278
# This value is not relevant inside the jail, but must remain for now. See
 
279
# the XXX in ivle.makeuser.make_conf_py.
 
280
jail_base = '/'
 
281
 
 
282
# The hostname for serving publicly accessible pages
 
283
public_host = %(public_host)r
 
284
 
 
285
# The URL under which the Subversion repositories are located.
 
286
svn_addr = %(svn_addr)r
 
287
 
 
288
# The login name for the owner of the jail
 
289
login = %(username)r
 
290
 
 
291
# The subversion-only password for the owner of the jail
 
292
svn_pass = %(svn_pass)r
 
293
""" % {'root_dir': ivle.conf.root_dir,
 
294
       'public_host': ivle.conf.public_host,
 
295
       'svn_addr': ivle.conf.svn_addr,
 
296
       'username': username,
 
297
       'svn_pass': svn_pass,
 
298
      })
 
299
    conf_file.close()
276
300
 
277
301
    # Make this file world-readable
278
302
    # (chmod 644 conf_path)