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

« back to all changes in this revision

Viewing changes to ivle/makeuser.py

  • Committer: William Grant
  • Date: 2009-04-28 04:50:39 UTC
  • Revision ID: grantw@unimelb.edu.au-20090428045039-ibb7gwtjrhe9osq3
Populate req.config in a cleaner manner.

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 md5
 
38
import hashlib
39
39
import os
40
40
import stat
41
41
import shutil
45
45
import filecmp
46
46
import logging
47
47
import ivle.conf
48
 
import ivle.db
49
48
import ivle.pulldown_subj
50
49
 
 
50
from ivle.database import ProjectGroup
 
51
 
51
52
def chown_to_webserver(filename):
52
53
    """
53
54
    Chowns a file so the web server user owns it.
73
74
 
74
75
    chown_to_webserver(path)
75
76
 
76
 
def rebuild_svn_config():
 
77
def rebuild_svn_config(store):
77
78
    """Build the complete SVN configuration file.
78
79
    """
79
 
    conn = ivle.db.DB()
80
 
    users = conn.get_users()
 
80
    users = store.find(ivle.database.User)
81
81
    groups = {}
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)
 
82
    # TODO: Populate groups with per-offering tutors/lecturers/etc.
87
83
    f = open(ivle.conf.svn_conf + ".new", "w")
88
84
    f.write("# IVLE SVN Repositories Configuration\n")
89
85
    f.write("# Auto-generated on %s\n" % time.asctime())
103
99
    os.rename(ivle.conf.svn_conf + ".new", ivle.conf.svn_conf)
104
100
    chown_to_webserver(ivle.conf.svn_conf)
105
101
 
106
 
def rebuild_svn_group_config():
 
102
def rebuild_svn_group_config(store):
107
103
    """Build the complete SVN configuration file for groups
108
104
    """
109
 
    conn = ivle.db.DB()
110
 
    groups = conn.get_all('project_group',
111
 
        ['groupid', 'groupnm', 'projectsetid'])
112
105
    f = open(ivle.conf.svn_group_conf + ".new", "w")
113
106
    f.write("# IVLE SVN Group Repositories Configuration\n")
114
107
    f.write("# Auto-generated on %s\n" % time.asctime())
115
108
    f.write("\n")
116
 
    for g in groups:
117
 
        projectsetid = g['projectsetid']
118
 
        offeringinfo = conn.get_offering_info(projectsetid)
119
 
        subj_short_name = offeringinfo['subj_short_name']
120
 
        year = offeringinfo['year']
121
 
        semester = offeringinfo['semester']
122
 
        reponame = "_".join([subj_short_name, year, semester, g['groupnm']])
 
109
    for group in store.find(ProjectGroup):
 
110
        offering = group.project_set.offering
 
111
        reponame = "_".join([offering.subject.short_name,
 
112
                             offering.semester.year,
 
113
                             offering.semester.semester,
 
114
                             group.name])
123
115
        f.write("[%s:/]\n"%reponame)
124
 
        users = conn.get_projectgroup_members(g['groupid'])
125
 
        for u in users:
126
 
            f.write("%s = rw\n"%u['login'])
 
116
        for user in group.members:
 
117
            f.write("%s = rw\n" % user.login)
127
118
        f.write("\n")
128
119
    f.close()
129
120
    os.rename(ivle.conf.svn_group_conf + ".new", ivle.conf.svn_group_conf)
132
123
def make_svn_auth(store, login, throw_on_error=True):
133
124
    """Setup svn authentication for the given user.
134
125
       Uses the given DB store object. Does not commit to the db.
135
 
       FIXME: create local.auth entry
136
126
    """
137
 
    passwd = md5.new(uuid.uuid4().bytes).digest().encode('hex')
 
127
    passwd = hashlib.md5(uuid.uuid4().bytes).hexdigest()
138
128
    if os.path.exists(ivle.conf.svn_auth_ivle):
139
129
        create = ""
140
130
    else:
184
174
    return (to_add, to_remove)
185
175
 
186
176
 
187
 
def make_jail(username, uid, force=True, svn_pass=None):
 
177
def make_jail(user, force=True):
188
178
    """Creates a new user's jail space, in the jail directory as configured in
189
179
    conf.py.
190
180
 
195
185
 
196
186
    Chowns the user's directory within the jail to the given UID.
197
187
 
198
 
    Note: This takes separate username and uid arguments. The UID need not
199
 
    *necessarily* correspond to a Unix username at all, if all you are
200
 
    planning to do is setuid to it. This allows the caller the freedom of
201
 
    deciding the binding between username and uid, if any.
202
 
 
203
188
    force: If false, exception if jail already exists for this user.
204
189
    If true (default), overwrites it, but preserves home directory.
205
 
 
206
 
    svn_pass: If provided this will be a string, the randomly-generated
207
 
    Subversion password for this user (if you happen to already have it).
208
 
    If not provided, it will be read from the database.
209
190
    """
210
191
    # MUST run as root or some of this may fail
211
192
    if os.getuid() != 0:
212
193
        raise Exception("Must run make_jail as root")
213
194
    
214
195
    # tempdir is for putting backup homes in
215
 
    tempdir = os.path.join(ivle.conf.jail_base, '__temp__')
 
196
    tempdir = os.path.join(ivle.conf.jail_src_base, '__temp__')
216
197
    if not os.path.exists(tempdir):
217
198
        os.makedirs(tempdir)
218
199
    elif not os.path.isdir(tempdir):
219
200
        os.unlink(tempdir)
220
201
        os.mkdir(tempdir)
221
 
    userdir = os.path.join(ivle.conf.jail_src_base, username)
 
202
    userdir = os.path.join(ivle.conf.jail_src_base, user.login)
222
203
    homedir = os.path.join(userdir, 'home')
223
 
    userhomedir = os.path.join(homedir, username)   # Return value
 
204
    userhomedir = os.path.join(homedir, user.login)   # Return value
224
205
 
225
206
    if os.path.exists(userdir):
226
207
        if not force:
232
213
        warnings.simplefilter('ignore')
233
214
        homebackup = os.tempnam(tempdir)
234
215
        warnings.resetwarnings()
235
 
        # Note: shutil.move does not behave like "mv" - it does not put a file
236
 
        # into a directory if it already exists, just fails. Therefore it is
237
 
        # not susceptible to tmpnam symlink attack.
 
216
        # Back up the /home directory, delete the entire jail, recreate the
 
217
        # jail directory tree, then copy the /home back
 
218
        # NOTE that shutil.move changed in Python 2.6, it now moves a
 
219
        # directory INTO the target (like `mv`), which it didn't use to do.
 
220
        # This code works regardless.
238
221
        shutil.move(homedir, homebackup)
239
222
        shutil.rmtree(userdir)
240
 
        os.makedirs(homedir)
 
223
        os.makedirs(userdir)
241
224
        shutil.move(homebackup, homedir)
242
225
        # Change the ownership of all the files to the right unixid
243
226
        logging.debug("chown %s's home directory files to uid %d"
244
 
            %(username, uid))
245
 
        os.chown(userhomedir, uid, uid)
246
 
        for root, dirs, files in os.walk(userhomedir):
247
 
            for fsobj in dirs + files:
248
 
                os.chown(os.path.join(root, fsobj), uid, uid)
 
227
            %(user.login, user.unixid))
 
228
        os.spawnvp(os.P_WAIT, 'chown', ['chown', '-R', '%d:%d' % (user.unixid,
 
229
                                        user.unixid), userhomedir])
249
230
    else:
250
231
        # No user jail exists
251
232
        # Set up the user's home directory
252
233
        os.makedirs(userhomedir)
253
234
        # Chown (and set the GID to the same as the UID).
254
 
        os.chown(userhomedir, uid, uid)
 
235
        os.chown(userhomedir, user.unixid, user.unixid)
255
236
        # Chmod to rwxr-xr-x (755)
256
237
        os.chmod(userhomedir, 0755)
257
238
 
258
 
    # There are 2 special files which need to be generated specific to this
259
 
    # user: ${python_site_packages}/lib/conf/conf.py and /etc/passwd.
260
 
    # "__" username "__" users are exempt (special)
261
 
    if not (username.startswith("__") and username.endswith("__")):
262
 
        make_conf_py(username, userdir, ivle.conf.jail_system, svn_pass)
263
 
        make_etc_passwd(username, userdir, ivle.conf.jail_system, uid)
 
239
    make_ivle_conf(user.login, userdir, user.svn_pass)
 
240
    make_etc_passwd(user.login, userdir, ivle.conf.jail_system, user.unixid)
264
241
 
265
242
    return userhomedir
266
243
 
267
 
def make_conf_py(username, user_jail_dir, staging_dir, svn_pass=None):
 
244
def make_ivle_conf(username, user_jail_dir, svn_pass):
268
245
    """
269
246
    Creates (overwriting any existing file, and creating directories) a
270
 
    file ${python_site_packages}/ivle/conf/conf.py in a given user's jail.
 
247
    file /etc/ivle/ivle.conf in a given user's jail.
271
248
    username: Username.
272
249
    user_jail_dir: User's jail dir, ie. ivle.conf.jail_base + username
273
 
    staging_dir: The dir with the staging copy of the jail. (With the
274
 
        template conf.py file).
275
 
    svn_pass: As with make_jail. User's SVN password, but if not supplied,
276
 
        will look up in the DB.
 
250
    svn_pass: User's SVN password.
277
251
    """
278
 
    template_conf_path = os.path.join(staging_dir,
279
 
            ivle.conf.python_site_packages[1:], "ivle/conf/conf.py")
280
 
    conf_path = os.path.join(user_jail_dir,
281
 
            ivle.conf.python_site_packages[1:], "ivle/conf/conf.py")
 
252
    conf_path = os.path.join(user_jail_dir, "etc/ivle/ivle.conf")
282
253
    os.makedirs(os.path.dirname(conf_path))
283
254
 
284
 
    # If svn_pass isn't supplied, grab it from the DB
285
 
    if svn_pass is None:
286
 
        dbconn = ivle.db.DB()
287
 
        svn_pass = dbconn.get_user(username).svn_pass
288
 
        dbconn.close()
289
 
 
290
 
    # Read the contents of the template conf file
291
 
    try:
292
 
        template_conf_file = open(template_conf_path, "r")
293
 
        template_conf_data = template_conf_file.read()
294
 
        template_conf_file.close()
295
 
    except:
296
 
        # Couldn't open template conf.py for some reason
297
 
        # Just treat it as empty file
298
 
        template_conf_data = ("# Warning: Problem building config script.\n"
299
 
                              "# Could not find template conf.py file.\n")
300
 
 
301
 
    conf_file = open(conf_path, "w")
302
 
    conf_file.write(template_conf_data)
303
 
    conf_file.write("\n# The login name for the owner of the jail\n")
304
 
    conf_file.write("login = %s\n" % repr(username))
305
 
    conf_file.write("\n")
306
 
    conf_file.write("# The subversion-only password for the owner of "
307
 
        "the jail\n")
308
 
    conf_file.write("svn_pass = %s\n" % repr(svn_pass))
309
 
    conf_file.close()
 
255
    # In the "in-jail" version of conf, we don't need MOST of the details
 
256
    # (it would be a security risk to have them here).
 
257
    # So we just write root_dir.
 
258
    conf_obj = ivle.config.Config(blank=True)
 
259
    conf_obj.filename = conf_path
 
260
    conf_obj['urls']['root'] = ivle.conf.root_dir
 
261
    conf_obj['urls']['public_host'] = ivle.conf.public_host
 
262
    conf_obj['urls']['svn_addr'] = ivle.conf.svn_addr
 
263
    conf_obj['user_info']['login'] = username
 
264
    conf_obj['user_info']['svn_pass'] = svn_pass
 
265
    conf_obj.write()
310
266
 
311
267
    # Make this file world-readable
312
268
    # (chmod 644 conf_path)
329
285
                      % (username, unixid, unixid, username))
330
286
    passwd_file.close()
331
287
 
332
 
def make_user_db(throw_on_error = True, **kwargs):
333
 
    """Creates a user's entry in the database, filling in all the fields.
334
 
    All arguments must be keyword args. They are the fields in the table.
335
 
    However, instead of supplying a "passhash", you must supply a
336
 
    "password" argument, which will be hashed internally.
337
 
    Also do not supply a state. All users are created in the "no_agreement"
338
 
    state.
339
 
    Also pulls the user's subjects using the configured subject pulldown
340
 
    module, and adds enrolments to the DB.
341
 
    Throws an exception if the user already exists.
342
 
    """
343
 
    dbconn = ivle.db.DB()
344
 
    dbconn.create_user(**kwargs)
345
 
    dbconn.close()
346
 
 
347
 
    if kwargs['password']:
348
 
        if os.path.exists(ivle.conf.svn_auth_local):
349
 
            create = ""
350
 
        else:
351
 
            create = "c"
352
 
        res = os.system("htpasswd -%smb %s %s %s" % (create,
353
 
                                                     ivle.conf.svn_auth_local,
354
 
                                                     kwargs['login'],
355
 
                                                     kwargs['password']))
356
 
        if res != 0 and throw_on_error:
357
 
            raise Exception("Unable to create local-auth for %s" % kwargs['login'])
358
 
 
359
 
    # Make sure the file is owned by the web server
360
 
    if create == "c":
361
 
        chown_to_webserver(ivle.conf.svn_auth_local)
362
 
 
363
 
    # Pulldown subjects and add enrolments
364
 
    ivle.pulldown_subj.enrol_user(kwargs['login'])
365
 
 
366
288
def mount_jail(login):
367
289
    # This is where we'll mount to...
368
290
    destdir = os.path.join(ivle.conf.jail_base, login)