diff options
-rw-r--r-- | exam/views.py | 26 | ||||
-rw-r--r-- | output/README.txt | 4 | ||||
-rwxr-xr-x | python_server.py | 5 |
3 files changed, 29 insertions, 6 deletions
diff --git a/exam/views.py b/exam/views.py index ed33c91..1cf2480 100644 --- a/exam/views.py +++ b/exam/views.py @@ -1,10 +1,9 @@ import random -import sys -import traceback import string +import os +import stat +from os.path import dirname, pardir, abspath, join, exists -from django.db import IntegrityError -from django.contrib.auth.models import User from django.contrib.auth import login, logout, authenticate from django.shortcuts import render_to_response, get_object_or_404, redirect from django.template import RequestContext @@ -12,11 +11,18 @@ from exam.models import Question, Quiz, Profile, Answer from exam.forms import UserRegisterForm, UserLoginForm from exam.xmlrpc_clients import python_server +# The directory where user data can be saved. +OUTPUT_DIR = abspath(join(dirname(__file__), pardir, 'output')) + def gen_key(no_of_chars): """Generate a random key of the number of characters.""" allowed_chars = string.digits+string.uppercase return ''.join([random.choice(allowed_chars) for i in range(no_of_chars)]) +def get_user_dir(user): + """Return the output directory for the user.""" + return join(OUTPUT_DIR, str(user.username)) + def index(request): """The start page. """ @@ -95,6 +101,15 @@ def start(request): ip = request.META['REMOTE_ADDR'] key = gen_key(10) new_quiz = Quiz(user=user, user_ip=ip, key=key) + + # Make user directory. + user_dir = get_user_dir(user) + if not exists(user_dir): + os.mkdir(user_dir) + # Make it rwx by others. + os.chmod(user_dir, stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH \ + | stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR \ + | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP) questions = [ str(_.id) for _ in Question.objects.all() ] random.shuffle(questions) @@ -131,7 +146,8 @@ def check(request, q_id): # Otherwise we were asked to check. We obtain the results via XML-RPC # with the code executed safely in a separate process (the python_server.py) # running as nobody. - success, err_msg = python_server.run_code(answer, question.test) + user_dir = get_user_dir(user) + success, err_msg = python_server.run_code(answer, question.test, user_dir) # Add the answer submitted. new_answer = Answer(question=question, answer=answer.strip()) diff --git a/output/README.txt b/output/README.txt new file mode 100644 index 0000000..3163ed4 --- /dev/null +++ b/output/README.txt @@ -0,0 +1,4 @@ +This directory contains files generated/saved by users as per their +username. The test executor will chdir into this user directory for each +user when they run the test. Do not delete this directory and ensure that +it is writeable by all.
\ No newline at end of file diff --git a/python_server.py b/python_server.py index debd73d..1670f90 100755 --- a/python_server.py +++ b/python_server.py @@ -4,13 +4,16 @@ and returns the output. It *should* be run as root and will run as the user 'nobody' so as to minimize any damange by errant code. """ import sys +import traceback from SimpleXMLRPCServer import SimpleXMLRPCServer import pwd import os +from os.path import isdir # Set the effective uid nobody = pwd.getpwnam('nobody') +os.setegid(nobody.pw_gid) os.seteuid(nobody.pw_uid) @@ -26,7 +29,7 @@ def run_code(answer, test_code, in_dir=None): A tuple: (success, error message). """ - if in_dir is not None: + if in_dir is not None and isdir(in_dir): os.chdir(in_dir) success = False |