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

« back to all changes in this revision

Viewing changes to lib/common/makeuser.py

  • Committer: mattgiuca
  • Date: 2008-06-16 12:31:27 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:780
dispatch/login.py: When displaying the login page, returns a 200, not a 403
    Forbidden.
    This is because "Forbidden" has the wrong semantic - it means "you will
    never get in here even if you auth", whereas we want to present the
    opportunity to auth.
    Some user agents interpret a 403 as defeat, and don't even present the
    page body.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
 
32
32
# TODO: When creating a new home directory, chown it to its owner
33
33
 
 
34
# TODO: In chown_to_webserver:
 
35
# Do not call os.system("chown www-data") - use Python lib
 
36
# and use the web server uid given in conf. (Several places).
 
37
 
34
38
import md5
35
39
import os
36
40
import stat
38
42
import time
39
43
import uuid
40
44
import warnings
41
 
 
 
45
import filecmp
42
46
import conf
43
47
import db
44
48
 
 
49
def chown_to_webserver(filename):
 
50
    """
 
51
    Chowns a file so the web server user owns it.
 
52
    (This is useful in setting up Subversion conf files).
 
53
    Assumes root.
 
54
    """
 
55
    try:
 
56
        os.system("chown -R www-data:www-data %s" % filename)
 
57
    except:
 
58
        pass
 
59
 
45
60
def make_svn_repo(login, throw_on_error=True):
46
61
    """Create a repository for the given user.
47
62
    """
54
69
        print repr(exc)
55
70
        if throw_on_error:
56
71
            raise
57
 
    try:
58
 
        os.system("chown -R www-data:www-data %s" % path)
59
 
    except Exception:
60
 
        pass
 
72
 
 
73
    chown_to_webserver(path)
61
74
 
62
75
def rebuild_svn_config():
63
76
    """Build the complete SVN configuration file.
88
101
        f.write("\n")
89
102
    f.close()
90
103
    os.rename(conf.svn_conf + ".new", conf.svn_conf)
 
104
    chown_to_webserver(conf.svn_conf)
91
105
 
92
106
def make_svn_config(login, throw_on_error=True):
93
107
    """Add an entry to the apache-svn config file for the given user.
101
115
    #f.write("@admin = rw\n")
102
116
    f.write("\n")
103
117
    f.close()
 
118
    chown_to_webserver(conf.svn_conf)
104
119
 
105
120
def make_svn_auth(login, throw_on_error=True):
106
121
    """Setup svn authentication for the given user.
120
135
    if res != 0 and throw_on_error:
121
136
        raise Exception("Unable to create ivle-auth for %s" % login)
122
137
 
 
138
    # Make sure the file is owned by the web server
 
139
    if create == "c":
 
140
        chown_to_webserver(conf.svn_auth_ivle)
 
141
 
123
142
    return passwd
124
143
 
125
 
def make_jail(username, uid, force=True):
 
144
def generate_manifest(basedir, targetdir, parent=''):
 
145
    """ From a basedir and a targetdir work out which files are missing or out 
 
146
    of date and need to be added/updated and which files are redundant and need 
 
147
    to be removed.
 
148
    
 
149
    parent: This is used for the recursive call to track the relative paths 
 
150
    that we have decended.
 
151
    """
 
152
    
 
153
    cmp = filecmp.dircmp(basedir, targetdir)
 
154
 
 
155
    # Add all new files and files that have changed
 
156
    to_add = [os.path.join(parent,x) for x in (cmp.left_only + cmp.diff_files)]
 
157
 
 
158
    # Remove files that are redundant
 
159
    to_remove = [os.path.join(parent,x) for x in cmp.right_only]
 
160
    
 
161
    # Recurse
 
162
    for d in cmp.common_dirs:
 
163
        newbasedir = os.path.join(basedir, d)
 
164
        newtargetdir = os.path.join(targetdir, d)
 
165
        newparent = os.path.join(parent, d)
 
166
        (sadd,sremove) = generate_manifest(newbasedir, newtargetdir, newparent)
 
167
        to_add += sadd
 
168
        to_remove += sremove
 
169
 
 
170
    return (to_add, to_remove)
 
171
 
 
172
 
 
173
def make_jail(username, uid, force=True, manifest=None, svn_pass=None):
126
174
    """Creates a new user's jail space, in the jail directory as configured in
127
175
    conf.py.
128
176
 
129
 
    This expects there to be a "template" directory within the jail root which
 
177
    This expects there to be a "staging" directory within the jail root which
130
178
    contains all the files for a sample student jail. It creates the student's
131
179
    directory in the jail root, by making a hard-link copy of every file in the
132
 
    template directory, recursively.
 
180
    staging directory, recursively.
133
181
 
134
182
    Returns the path to the user's home directory.
135
183
 
142
190
 
143
191
    force: If false, exception if jail already exists for this user.
144
192
    If true (default), overwrites it, but preserves home directory.
 
193
 
 
194
    manifest: If provided this will be a pair (to_add, to_remove) of files or
 
195
    directories to add or remove from the jail.
 
196
 
 
197
    svn_pass: If provided this will be a string, the randomly-generated
 
198
    Subversion password for this user (if you happen to already have it).
 
199
    If not provided, it will be read from the database.
145
200
    """
146
201
    # MUST run as root or some of this may fail
147
202
    if os.getuid() != 0:
148
203
        raise Exception("Must run make_jail as root")
149
204
    
150
 
    templatedir = os.path.join(conf.jail_base, 'template')
151
 
    if not os.path.isdir(templatedir):
152
 
        raise Exception("Template jail directory does not exist: " +
153
 
            templatedir)
 
205
    stagingdir = os.path.join(conf.jail_base, '__staging__')
 
206
    if not os.path.isdir(stagingdir):
 
207
        raise Exception("Staging jail directory does not exist: " +
 
208
            stagingdir)
154
209
    # tempdir is for putting backup homes in
155
 
    tempdir = os.path.join(conf.jail_base, 'temp')
 
210
    tempdir = os.path.join(conf.jail_base, '__temp__')
156
211
    if not os.path.exists(tempdir):
157
212
        os.makedirs(tempdir)
158
213
    elif not os.path.isdir(tempdir):
179
234
            # the backup will be un-made.
180
235
            # XXX This will still leave the user's jail in an unusable state,
181
236
            # but at least they won't lose their files.
182
 
            shutil.rmtree(userdir)
183
 
 
184
 
            # Hard-link (copy aliasing) the entire tree over
185
 
            linktree(templatedir, userdir)
 
237
            if manifest:
 
238
                (to_add, to_remove) = manifest
 
239
                # Remove redundant files and directories
 
240
                for d in to_remove:
 
241
                    dst = os.path.join(userdir, d)
 
242
                    src = os.path.join(stagingdir, d)
 
243
                    if os.path.isdir(dst):
 
244
                        shutil.rmtree(dst)
 
245
                    elif os.path.isfile(dst):
 
246
                        os.remove(dst)
 
247
                # Add new files
 
248
                for d in to_add:
 
249
                    dst = os.path.join(userdir, d)
 
250
                    src = os.path.join(stagingdir, d)
 
251
                    # Clear the previous file/dir
 
252
                    if os.path.isdir(dst):
 
253
                        shutil.rmtree(dst)
 
254
                    elif os.path.isfile(dst):
 
255
                        os.remove(dst)
 
256
                    # Link the file/dirs
 
257
                    if os.path.isdir(src):
 
258
                        linktree(src, dst)
 
259
                    elif os.path.isfile(src):
 
260
                        os.link(src, dst)
 
261
                    
 
262
            else:
 
263
                # No manifest, do a full rebuild
 
264
                shutil.rmtree(userdir)
 
265
                # Hard-link (copy aliasing) the entire tree over
 
266
                linktree(stagingdir, userdir)
186
267
        finally:
187
268
            # Set up the user's home directory (restore backup)
188
269
            # First make sure the directory is empty and its parent exists
194
275
            # directory). But it shouldn't fail as homedir should not exist.
195
276
            os.makedirs(homedir)
196
277
            shutil.move(homebackup, homedir)
197
 
        return os.path.join(homedir, username)
 
278
        userhomedir = os.path.join(homedir, username)   # Return value
198
279
    else:
199
280
        # No user jail exists
200
281
        # Hard-link (copy aliasing) the entire tree over
201
 
        linktree(templatedir, userdir)
 
282
        linktree(stagingdir, userdir)
202
283
 
203
284
        # Set up the user's home directory
204
285
        userhomedir = os.path.join(homedir, username)
207
288
        os.chown(userhomedir, uid, uid)
208
289
        # Chmod to rwxr-xr-x (755)
209
290
        os.chmod(userhomedir, 0755)
210
 
        return userhomedir
 
291
 
 
292
    # There is 1 special file which should not be hard-linked, but instead
 
293
    # generated specific to this user: /opt/ivle/lib/conf/conf.py.
 
294
    # "__" username "__" users are exempt (special)
 
295
    if not (username.startswith("__") and username.endswith("__")):
 
296
        make_conf_py(username, userdir, stagingdir, svn_pass)
 
297
 
 
298
    return userhomedir
 
299
 
 
300
def make_conf_py(username, user_jail_dir, staging_dir, svn_pass=None):
 
301
    """
 
302
    Creates (overwriting any existing file) a file /opt/ivle/lib/conf/conf.py
 
303
    in a given user's jail.
 
304
    username: Username.
 
305
    user_jail_dir: User's jail dir, ie. conf.jail_base + username
 
306
    staging_dir: The dir with the staging copy of the jail. (With the
 
307
        template conf.py file).
 
308
    svn_pass: As with make_jail. User's SVN password, but if not supplied,
 
309
        will look up in the DB.
 
310
    """
 
311
    # Note: It is important to delete this file and recreate it (somewhat
 
312
    # ironically beginning by pasting the same contents in again), rather than
 
313
    # simply appending.
 
314
    # Note that all files initially are aliased, so appending would result
 
315
    # in a massive aliasing problem. Deleting and recreating ensures that
 
316
    # the conf.py files are unique to each jail.
 
317
    template_conf_path = os.path.join(staging_dir,"opt/ivle/lib/conf/conf.py")
 
318
    conf_path = os.path.join(user_jail_dir, "opt/ivle/lib/conf/conf.py")
 
319
 
 
320
    # If svn_pass isn't supplied, grab it from the DB
 
321
    if svn_pass is None:
 
322
        dbconn = db.DB()
 
323
        svn_pass = dbconn.get_user(username).svn_pass
 
324
        dbconn.close()
 
325
 
 
326
    # Read the contents of the template conf file
 
327
    try:
 
328
        template_conf_file = open(template_conf_path, "r")
 
329
        template_conf_data = template_conf_file.read()
 
330
        template_conf_file.close()
 
331
    except:
 
332
        # Couldn't open template conf.py for some reason
 
333
        # Just treat it as empty file
 
334
        template_conf_data = ""
 
335
 
 
336
    # Remove the target conf file if it exists
 
337
    try:
 
338
        os.remove(conf_path)
 
339
    except OSError:
 
340
        pass
 
341
    conf_file = open(conf_path, "w")
 
342
    conf_file.write(template_conf_data)
 
343
    conf_file.write("\n# The login name for the owner of the jail\n")
 
344
    conf_file.write("login = %s\n" % repr(username))
 
345
    conf_file.write("\n")
 
346
    conf_file.write("# The subversion-only password for the owner of "
 
347
        "the jail\n")
 
348
    conf_file.write("svn_pass = %s\n" % repr(svn_pass))
 
349
    conf_file.close()
 
350
 
 
351
    # Make this file world-readable
 
352
    # (chmod 644 conf_path)
 
353
    os.chmod(conf_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP
 
354
                        | stat.S_IROTH)
211
355
 
212
356
def linktree(src, dst):
213
357
    """Recursively hard-link a directory tree using os.link().
248
392
    if errors:
249
393
        raise Exception, errors
250
394
 
251
 
def make_user_db(**kwargs):
 
395
def make_user_db(throw_on_error = True, **kwargs):
252
396
    """Creates a user's entry in the database, filling in all the fields.
253
397
    All arguments must be keyword args. They are the fields in the table.
254
398
    However, instead of supplying a "passhash", you must supply a
273
417
        if res != 0 and throw_on_error:
274
418
            raise Exception("Unable to create local-auth for %s" % kwargs['login'])
275
419
 
 
420
    # Make sure the file is owned by the web server
 
421
    if create == "c":
 
422
        chown_to_webserver(conf.svn_auth_local)