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

« back to all changes in this revision

Viewing changes to lib/common/interpret.py

  • Committer: dcoles
  • Date: 2008-07-18 02:40:58 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:912
Makeuser: Makeuser will now chown all files in a users home directory to the
unixid provided by the database. This means remakeallusers.py can be used to
update everyones unixids after a database change. The makeuser script will also 
no longer generate a random unixid when one is not given on the command line.

Database: Change to database so that a sequence is used by default. The allowed  
range is 1000-29999 (let's start at 5000, because 1000+ is used by adduser.  
Reference: http://www.debian.org/doc/debian-policy/ch-opersys.html)
See SF Bug '[ 2012190 ] Student UID generation'
Migration script will reallocate all users a new unixid from the sequence.

Usermgt-Server: Now no longer generates a random unixid. Rely on the database 
to come up with a new sequence number.

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
# This can be resolved but needs careful sanitisation. See fixup_environ.
29
29
 
30
30
from common import studpath
 
31
from common import db
 
32
from common.util import IVLEError, IVLEJailError
31
33
import conf
32
34
import functools
33
35
 
42
44
 
43
45
CGI_BLOCK_SIZE = 65535
44
46
 
45
 
def interpret_file(req, owner, jail_dir, filename, interpreter):
 
47
uids = {}
 
48
 
 
49
def get_uid(login):
 
50
    """Get the unix uid corresponding to the given login name.
 
51
       If it is not in the dictionary of uids, then consult the
 
52
       database and retrieve an update of the user table."""
 
53
    global uids
 
54
    if login in uids:
 
55
        return uids[login]
 
56
 
 
57
    conn = db.DB()
 
58
    res = conn.get_all('login', ['login', 'unixid'])
 
59
    def repack(flds):
 
60
        return (flds['login'], flds['unixid'])
 
61
    uids = dict(map(repack,res))
 
62
 
 
63
    return uids[login]
 
64
 
 
65
def interpret_file(req, owner, jail_dir, filename, interpreter, gentle=True):
46
66
    """Serves a file by interpreting it using one of IVLE's builtin
47
67
    interpreters. All interpreters are intended to run in the user's jail. The
48
68
    jail location is provided as an argument to the interpreter but it is up
54
74
    filename: Absolute filename within the user's jail.
55
75
    interpreter: A function object to call.
56
76
    """
57
 
    # Make sure the file exists (otherwise some interpreters may not actually
58
 
    # complain).
59
 
    # Don't test for execute permission, that will only be required for
60
 
    # certain interpreters.
 
77
    # We can't test here whether or not the target file actually exists,
 
78
    # because the apache user may not have permission. Instead we have to
 
79
    # rely on the interpreter generating an error.
61
80
    if filename.startswith(os.sep):
62
81
        filename_abs = filename
63
82
        filename_rel = filename[1:]
65
84
        filename_abs = os.path.join(os.sep, filename)
66
85
        filename_rel = filename
67
86
 
68
 
    if not os.access(os.path.join(jail_dir, filename_rel), os.R_OK):
69
 
        req.throw_error(req.HTTP_NOT_FOUND)
70
 
 
71
87
    # Get the UID of the owner of the file
72
88
    # (Note: files are executed by their owners, not the logged in user.
73
89
    # This ensures users are responsible for their own programs and also
74
90
    # allows them to be executed by the public).
75
 
    uid = req.user.unixid
 
91
    uid = get_uid(owner)
76
92
 
77
93
    # Split up req.path again, this time with respect to the jail
78
94
    (working_dir, _) = os.path.split(filename_abs)
83
99
    # (Note that paths "relative" to the jail actually begin with a '/' as
84
100
    # they are absolute in the jailspace)
85
101
 
86
 
    return interpreter(uid, jail_dir, working_dir, filename_abs, req)
 
102
    return interpreter(uid, jail_dir, working_dir, filename_abs, req,
 
103
                       gentle)
87
104
 
88
105
class CGIFlags:
89
 
    """Stores flags regarding the state of reading CGI output."""
90
 
    def __init__(self):
 
106
    """Stores flags regarding the state of reading CGI output.
 
107
       If this is to be gentle, detection of invalid headers will result in an
 
108
       HTML warning."""
 
109
    def __init__(self, begentle=True):
 
110
        self.gentle = begentle
91
111
        self.started_cgi_body = False
92
112
        self.got_cgi_headers = False
93
113
        self.wrote_html_warning = False
95
115
        self.headers = {}       # Header names : values
96
116
 
97
117
def execute_cgi(interpreter, trampoline, uid, jail_dir, working_dir,
98
 
                script_path, req):
 
118
                script_path, req, gentle):
99
119
    """
100
120
    trampoline: Full path on the local system to the CGI wrapper program
101
121
        being executed.
150
170
    # process_cgi_line: Reads a single line of CGI output and processes it.
151
171
    # Prints to req, and also does fancy HTML warnings if Content-Type
152
172
    # omitted.
153
 
    cgiflags = CGIFlags()
 
173
    cgiflags = CGIFlags(gentle)
154
174
 
155
175
    # Read from the process's stdout into req
156
176
    data = pid.stdout.read(CGI_BLOCK_SIZE)
182
202
        # Break data into lines of CGI header data. 
183
203
        linebuf = cgiflags.linebuf + data
184
204
        # First see if we can split all header data
185
 
        split = linebuf.split('\r\n\r\n', 1)
186
 
        if len(split) == 1:
187
 
            # Allow UNIX newlines instead
188
 
            split = linebuf.split('\n\n', 1)
 
205
        # We need to get the double CRLF- or LF-terminated headers, whichever
 
206
        # is smaller, as either sequence may appear somewhere in the body.
 
207
        usplit = linebuf.split('\n\n', 1)
 
208
        wsplit = linebuf.split('\r\n\r\n', 1)
 
209
        split = len(usplit[0]) > len(wsplit[0]) and wsplit or usplit
189
210
        if len(split) == 1:
190
211
            # Haven't seen all headers yet. Buffer and come back later.
191
212
            cgiflags.linebuf = linebuf
211
232
            if len(split) == 1:
212
233
                split = headers.split('\n', 1)
213
234
 
 
235
        # Is this an internal IVLE error condition?
 
236
        hs = cgiflags.headers
 
237
        if 'X-IVLE-Error-Type' in hs:
 
238
            t = hs['X-IVLE-Error-Type']
 
239
            if t == IVLEError.__name__:
 
240
                raise IVLEError(int(hs['X-IVLE-Error-Code']),
 
241
                                hs['X-IVLE-Error-Message'])
 
242
            else:
 
243
                try:
 
244
                    raise IVLEJailError(hs['X-IVLE-Error-Type'],
 
245
                                        hs['X-IVLE-Error-Message'],
 
246
                                        hs['X-IVLE-Error-Info'])
 
247
                except KeyError:
 
248
                    raise IVLEError(500, 'bad error headers written by CGI')
 
249
 
214
250
        # Check to make sure the required headers were written
215
 
        if cgiflags.wrote_html_warning:
 
251
        if cgiflags.wrote_html_warning or not cgiflags.gentle:
216
252
            # We already reported an error, that's enough
217
253
            pass
218
254
        elif "Content-Type" in cgiflags.headers:
245
281
    try:
246
282
        name, value = line.split(':', 1)
247
283
    except ValueError:
 
284
        # If we are being gentle, we want to help the user understand what
 
285
        # went wrong. Otherwise, we bail out.
 
286
        if not cgiflags.gentle:
 
287
            raise
248
288
        # No colon. The user did not write valid headers.
249
289
        if len(cgiflags.headers) == 0:
250
290
            # First line was not a header line. We can assume this is not
276
316
        try:
277
317
            req.status = int(value.split(' ', 1)[0])
278
318
        except ValueError:
 
319
            if not cgiflags.gentle:
 
320
                # This isn't user code, so it should be good.
 
321
                # Get us out of here!
 
322
                raise
279
323
            message = """The "Status" CGI header was invalid. You need to
280
324
print a number followed by a message, such as "302 Found"."""
281
325
            write_html_warning(req, message)