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

« back to all changes in this revision

Viewing changes to ivle/interpret.py

  • Committer: me at id
  • Date: 2009-01-15 01:06:33 UTC
  • mto: This revision was merged to the branch mainline in revision 1090.
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:branches%2Fstorm:1144
ivle.auth.* now uses Storm, and not ivle.(db|user). This changes the interface
    somewhat (lots of things take a 'store' argument), so fix callers.

ivle.db: Remove user_authenticate; it's now a method of ivle.database.User.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
# Runs a student script in a safe execution environment.
23
23
 
24
24
from ivle import studpath
 
25
from ivle import db
25
26
from ivle.util import IVLEError, IVLEJailError
26
27
import ivle.conf
27
28
 
38
39
 
39
40
CGI_BLOCK_SIZE = 65535
40
41
 
 
42
uids = {}
 
43
 
 
44
def get_uid(login):
 
45
    """Get the unix uid corresponding to the given login name.
 
46
       If it is not in the dictionary of uids, then consult the
 
47
       database and retrieve an update of the user table."""
 
48
    global uids
 
49
    if login in uids:
 
50
        return uids[login]
 
51
 
 
52
    conn = db.DB()
 
53
    res = conn.get_all('login', ['login', 'unixid'])
 
54
    def repack(flds):
 
55
        return (flds['login'], flds['unixid'])
 
56
    uids = dict(map(repack,res))
 
57
 
 
58
    return uids[login]
 
59
 
41
60
def interpret_file(req, owner, jail_dir, filename, interpreter, gentle=True):
42
61
    """Serves a file by interpreting it using one of IVLE's builtin
43
62
    interpreters. All interpreters are intended to run in the user's jail. The
45
64
    to the individual interpreters to create the jail.
46
65
 
47
66
    req: An IVLE request object.
48
 
    owner: The user who owns the file being served.
 
67
    owner: Username of the user who owns the file being served.
49
68
    jail_dir: Absolute path to the user's jail.
50
69
    filename: Absolute filename within the user's jail.
51
70
    interpreter: A function object to call.
60
79
        filename_abs = os.path.join(os.sep, filename)
61
80
        filename_rel = filename
62
81
 
 
82
    # Get the UID of the owner of the file
63
83
    # (Note: files are executed by their owners, not the logged in user.
64
84
    # This ensures users are responsible for their own programs and also
65
85
    # allows them to be executed by the public).
 
86
    uid = get_uid(owner)
66
87
 
67
88
    # Split up req.path again, this time with respect to the jail
68
89
    (working_dir, _) = os.path.split(filename_abs)
73
94
    # (Note that paths "relative" to the jail actually begin with a '/' as
74
95
    # they are absolute in the jailspace)
75
96
 
76
 
    return interpreter(owner.unixid, jail_dir, working_dir, filename_abs, req,
 
97
    return interpreter(uid, jail_dir, working_dir, filename_abs, req,
77
98
                       gentle)
78
99
 
79
100
class CGIFlags:
134
155
        del os.environ[k]
135
156
    for (k,v) in req.get_cgi_environ().items():
136
157
        os.environ[k] = v
137
 
    fixup_environ(req, script_path)
 
158
    fixup_environ(req)
138
159
 
139
160
    # usage: tramp uid jail_dir working_dir script_path
140
161
    pid = subprocess.Popen(
141
 
        [trampoline, str(uid), ivle.conf.jail_base, ivle.conf.jail_src_base,
142
 
         ivle.conf.jail_system, jail_dir, working_dir, interpreter,
 
162
        [trampoline, str(uid), jail_dir, working_dir, interpreter,
143
163
        script_path],
144
164
        stdin=f, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
145
165
        cwd=tramp_dir)
359
379
    # python-server-page
360
380
}
361
381
 
362
 
def fixup_environ(req, script_path):
 
382
def fixup_environ(req):
363
383
    """Assuming os.environ has been written with the CGI variables from
364
384
    apache, make a few changes for security and correctness.
365
385
 
385
405
        del env['PATH']
386
406
    except: pass
387
407
 
 
408
    # Remove SCRIPT_FILENAME. Not part of CGI spec (see SCRIPT_NAME).
 
409
 
 
410
    # PATH_INFO is wrong because the script doesn't physically exist.
 
411
    # Apache makes it relative to the "serve" app. It should actually be made
 
412
    # relative to the student's script. intepretservice does that in the jail,
 
413
    # so here we just clear it.
 
414
    env['PATH_INFO'] = ''
 
415
    env['PATH_TRANSLATED'] = ''
 
416
 
388
417
    # CGI specifies that REMOTE_HOST SHOULD be set, and MAY just be set to
389
418
    # REMOTE_ADDR. Since Apache does not appear to set this, set it to
390
419
    # REMOTE_ADDR.
391
420
    if 'REMOTE_HOST' not in env and 'REMOTE_ADDR' in env:
392
421
        env['REMOTE_HOST'] = env['REMOTE_ADDR']
393
422
 
394
 
    env['PATH_INFO'] = ''
395
 
    del env['PATH_TRANSLATED']
396
 
 
397
 
    normuri = os.path.normpath(req.uri)
398
 
    env['SCRIPT_NAME'] = normuri
399
 
 
400
423
    # SCRIPT_NAME is the path to the script WITHOUT PATH_INFO.
401
 
    # We don't care about these if the script is null (ie. noop).
402
 
    # XXX: We check for /home because we don't want to interfere with
403
 
    # CGIRequest, which fileservice still uses.
404
 
    if script_path and script_path.startswith('/home'):
405
 
        normscript = os.path.normpath(script_path)
406
 
 
407
 
        uri_into_jail = studpath.url_to_jailpaths(os.path.normpath(req.path))[2]
408
 
 
409
 
        # PATH_INFO is wrong because the script doesn't physically exist.
410
 
        env['PATH_INFO'] = uri_into_jail[len(normscript):]
411
 
        if len(env['PATH_INFO']) > 0:
412
 
            env['SCRIPT_NAME'] = normuri[:-len(env['PATH_INFO'])]
 
424
    script_name = req.uri
 
425
    env['SCRIPT_NAME'] = script_name
413
426
 
414
427
    # SERVER_SOFTWARE is actually not Apache but IVLE, since we are
415
428
    # custom-making the CGI request.
418
431
    # Additional environment variables
419
432
    username = studpath.url_to_jailpaths(req.path)[0]
420
433
    env['HOME'] = os.path.join('/home', username)
421
 
 
422
 
class ExecutionError(Exception):
423
 
    pass
424
 
 
425
 
def execute_raw(user, jail_dir, working_dir, binary, args):
426
 
    '''Execute a binary in a user's jail, returning the raw output.
427
 
 
428
 
    The binary is executed in the given working directory with the given
429
 
    args. A tuple of (stdout, stderr) is returned.
430
 
    '''
431
 
 
432
 
    tramp = location_cgi_python
433
 
    tramp_dir = os.path.split(location_cgi_python)[0]
434
 
 
435
 
    # Fire up trampoline. Vroom, vroom.
436
 
    proc = subprocess.Popen(
437
 
        [tramp, str(user.unixid), ivle.conf.jail_base,
438
 
         ivle.conf.jail_src_base, ivle.conf.jail_system, jail_dir,
439
 
         working_dir, binary] + args,
440
 
        stdin=subprocess.PIPE, stdout=subprocess.PIPE,
441
 
        stderr=subprocess.PIPE, cwd=tramp_dir, close_fds=True)
442
 
 
443
 
    (stdout, stderr) = proc.communicate()
444
 
    exitcode = proc.returncode
445
 
 
446
 
    if exitcode != 0:
447
 
        raise ExecutionError('subprocess ended with code %d, stderr %s' %
448
 
                             (exitcode, proc.stderr.read()))
449
 
    return (stdout, stderr)