39
40
CGI_BLOCK_SIZE = 65535
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."""
53
res = conn.get_all('login', ['login', 'unixid'])
55
return (flds['login'], flds['unixid'])
56
uids = dict(map(repack,res))
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
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)
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,
144
164
stdin=f, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
408
# Remove SCRIPT_FILENAME. Not part of CGI spec (see SCRIPT_NAME).
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'] = ''
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
391
420
if 'REMOTE_HOST' not in env and 'REMOTE_ADDR' in env:
392
421
env['REMOTE_HOST'] = env['REMOTE_ADDR']
394
env['PATH_INFO'] = ''
395
del env['PATH_TRANSLATED']
397
normuri = os.path.normpath(req.uri)
398
env['SCRIPT_NAME'] = normuri
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)
407
uri_into_jail = studpath.to_home_path(os.path.normpath(req.path))
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
414
427
# SERVER_SOFTWARE is actually not Apache but IVLE, since we are
415
428
# custom-making the CGI request.
416
429
env['SERVER_SOFTWARE'] = "IVLE/" + str(ivle.conf.ivle_version)
418
431
# Additional environment variables
419
username = split_path(req.path)[0]
432
username = studpath.url_to_jailpaths(req.path)[0]
420
433
env['HOME'] = os.path.join('/home', username)
422
class ExecutionError(Exception):
425
def execute_raw(user, jail_dir, working_dir, binary, args):
426
'''Execute a binary in a user's jail, returning the raw output.
428
The binary is executed in the given working directory with the given
429
args. A tuple of (stdout, stderr) is returned.
432
tramp = location_cgi_python
433
tramp_dir = os.path.split(location_cgi_python)[0]
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)
443
(stdout, stderr) = proc.communicate()
444
exitcode = proc.returncode
447
raise ExecutionError('subprocess ended with code %d, stderr %s' %
448
(exitcode, proc.stderr.read()))
449
return (stdout, stderr)