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

« back to all changes in this revision

Viewing changes to bin/trampoline/trampoline.c

  • Committer: David Coles
  • Date: 2010-07-28 10:52:48 UTC
  • mfrom: (1791.2.10 mediahandlers)
  • Revision ID: coles.david@gmail.com-20100728105248-zvbn9g72v1nsskvd
A series of HTML5 based media handlers using the <audio> and <video> tags.  
This replaces the previous page that just showed a download link (which is 
already available on the menu).

Also solves issue where media files were downloaded by the client twice (once 
in an AJAX request intended only for text).

Known issues:
    * Bug #588285: External BHO will not be able to play media due to not
      having IVLE cookie.
    * Bug #610745: Does not correctly preview revisions
    * Bug #610780: Ogg media does not work in Chromium

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* IVLE - Informatics Virtual Learning Environment
 
2
 * Copyright (C) 2007-2008 The University of Melbourne
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 *
 
18
 * Program: Trampoline
 
19
 * Author:  Tom Conway, Matt Giuca
 
20
 * Date:    20/12/2007
 
21
 *
 
22
 * This program runs a given program in a given working dir.
 
23
 * First, it chroots to a jail path and setuids to a given user ID.
 
24
 * This is intented to provide a safe execution environment for arbitrary
 
25
 * programs and services.
 
26
 *
 
27
 * Scripts (such as Python programs) should be executed by supplying
 
28
 * "/usr/bin/python" as the program, and the script as the first argument.
 
29
 *
 
30
 * Must run as root. Will safely setuid to the supplied uid, checking that it
 
31
 * is not root. Recommended that the file is set up as follows:
 
32
 *  sudo chown root:root trampoline; sudo chroot +s trampoline
 
33
 */
 
34
 
 
35
#define _XOPEN_SOURCE
 
36
#define _BSD_SOURCE
 
37
 
 
38
#include <stdio.h>
 
39
#include <stdlib.h>
 
40
#include <string.h>
 
41
#include <unistd.h>
 
42
#include <syslog.h>
 
43
#include <sys/mount.h>
 
44
#include <sys/types.h>
 
45
#include <sys/stat.h>
 
46
#include <sys/time.h>
 
47
#include <sys/resource.h>
 
48
#include <grp.h>
 
49
#include <limits.h>
 
50
#include <signal.h>
 
51
 
 
52
/* conf.h is admin-configured by the setup process.
 
53
 * It defines jail_base.
 
54
 */
 
55
#include "conf.h"
 
56
 
 
57
#include "norm.h"
 
58
 
 
59
/* Returns TRUE if the given uid is allowed to execute trampoline.
 
60
 * Only root or the web server should be allowed to execute.
 
61
 * This is determined by the whitelist allowed_uids in conf.h.
 
62
 */
 
63
int uid_allowed(int uid)
 
64
{
 
65
    int i;
 
66
    /* root is always allowed to execute trampoline */
 
67
    if (uid == 0)
 
68
        return 1;
 
69
    /* loop over all allowed_uids */
 
70
    for (i=(sizeof(allowed_uids)/sizeof(*allowed_uids))-1; i>=0; i--)
 
71
    {
 
72
        if (allowed_uids[i] == uid)
 
73
            return 1;
 
74
    }
 
75
    /* default to disallowing */
 
76
    return 0;
 
77
}
 
78
 
 
79
/* Turn the process into a daemon using the standard
 
80
 * 2-fork technique.
 
81
 */
 
82
void daemonize(void)
 
83
{
 
84
    pid_t pid, sid;
 
85
 
 
86
    /* already a daemon */
 
87
    if ( getppid() == 1 ) return;
 
88
 
 
89
    /* Fork off the parent process */
 
90
    pid = fork();
 
91
    if (pid < 0) {
 
92
        exit(1);
 
93
    }
 
94
    /* If we got a good PID, then we can exit the parent process. */
 
95
    if (pid > 0) {
 
96
        exit(0);
 
97
    }
 
98
 
 
99
    /* At this point we are executing as the child process */
 
100
 
 
101
    /* Change the file mode mask */
 
102
    umask(022);
 
103
 
 
104
    /* Create a new SID for the child process */
 
105
    sid = setsid();
 
106
    if (sid < 0) {
 
107
        exit(1);
 
108
    }
 
109
 
 
110
    /* Change the current working directory.  This prevents the current
 
111
       directory from being locked; hence not being able to remove it. */
 
112
    if ((chdir("/")) < 0) {
 
113
        exit(1);
 
114
    }
 
115
 
 
116
    /* Redirect standard files to /dev/null */
 
117
    freopen( "/dev/null", "r", stdin);
 
118
    freopen( "/dev/null", "w", stdout);
 
119
    freopen( "/dev/null", "w", stderr);
 
120
}
 
121
 
 
122
static void usage(const char* nm)
 
123
{
 
124
    fprintf(stderr,
 
125
        "usage: %s [-d] [-u] <uid> <base> <src> <system> <jail> <cwd> <program> [args...]\n", nm);
 
126
    fprintf(stderr, "  -d       \tDaemonize\n");
 
127
    fprintf(stderr, "  -u       \tPrint usage\n");
 
128
    fprintf(stderr, "  <uid>    \tUID to run program as\n");
 
129
    fprintf(stderr, "  <base>   \tDirectory that jails will be mounted in\n");
 
130
    fprintf(stderr, "  <src>    \tDirectory containing users jail data\n");
 
131
    fprintf(stderr, "  <system> \tDirectory containing main jail file system\n");
 
132
    fprintf(stderr, "  <jail>   \tDirectory of users mounted jail\n");
 
133
    fprintf(stderr, "  <cwd>    \tDirectory inside the jail to change dir to\n");
 
134
    fprintf(stderr, "  <program>\tProgram inside jail to execute\n");
 
135
    exit(1);
 
136
}
 
137
 
 
138
#ifdef IVLE_AUFS_JAILS
 
139
/* Die more pleasantly if mallocs fail. */
 
140
void *die_if_null(void *ptr)
 
141
{
 
142
    if (ptr == NULL)
 
143
    {
 
144
        perror("not enough memory");
 
145
        exit(1);
 
146
    }
 
147
    return ptr;
 
148
}
 
149
 
 
150
int checked_mount(const char *source, const char *target,
 
151
                  const char *filesystemtype, unsigned long mountflags,
 
152
                  const void *data)
 
153
{
 
154
    int result = mount(source, target, filesystemtype, mountflags, data);
 
155
    if (result)
 
156
    {
 
157
        syslog(LOG_ERR, "could not mount %s on %s\n", source, target);
 
158
        perror("could not mount");
 
159
        exit(1);
 
160
    }
 
161
 
 
162
    return result;
 
163
}
 
164
 
 
165
 
 
166
/* Find the path of the user components of a jail, given a mountpoint. */
 
167
char *jail_src(const char *jail_src_base, const char *jail_base,
 
168
               const char *jailpath)
 
169
{
 
170
    char* src;
 
171
    int srclen;
 
172
    int dstlen;
 
173
 
 
174
    srclen = strlen(jail_src_base);
 
175
    dstlen = strlen(jail_base);
 
176
 
 
177
    src = die_if_null(malloc(strlen(jailpath) + (srclen - dstlen) + 1));
 
178
    strcpy(src, jail_src_base);
 
179
    strcat(src, jailpath+dstlen);
 
180
 
 
181
    return src;
 
182
}
 
183
 
 
184
/* Check for the validity of a jail in the given path, mounting it if it looks
 
185
 * empty.
 
186
 * TODO: Updating /etc/mtab would be nice. */
 
187
void mount_if_needed(const char *jail_src_base, const char *jail_base,
 
188
                     const char *jail_system, const char *jailpath)
 
189
{
 
190
    char *jailsrc;
 
191
    char *jaillib;
 
192
    char *source_bits;
 
193
    char *target_bits;
 
194
 
 
195
    /* Check if there is something useful in the jail. If not, it's probably
 
196
     * not mounted. */
 
197
    jaillib = die_if_null(malloc(strlen(jailpath) + 5));
 
198
    sprintf(jaillib, "%s/lib", jailpath);
 
199
 
 
200
    if (access(jaillib, F_OK))
 
201
    {
 
202
        /* No /lib? Mustn't be mounted. Mount it, creating the dir if needed. */
 
203
        if (access(jailpath, F_OK))
 
204
        {
 
205
             if(mkdir(jailpath, 0755))
 
206
             {
 
207
                 syslog(LOG_ERR, "could not create mountpoint %s\n", jailpath);
 
208
                 perror("could not create jail mountpoint");
 
209
                 exit(1);
 
210
             }
 
211
             syslog(LOG_NOTICE, "created mountpoint %s\n", jailpath);
 
212
        }
 
213
 
 
214
        jailsrc = jail_src(jail_src_base, jail_base, jailpath);
 
215
        checked_mount(jail_system, jailpath, NULL, MS_BIND | MS_RDONLY, NULL);
 
216
 
 
217
        source_bits = die_if_null(malloc(strlen(jailsrc) + 5 + 1));
 
218
        target_bits = die_if_null(malloc(strlen(jailpath) + 5 + 1));
 
219
        sprintf(source_bits, "%s/home", jailsrc);
 
220
        sprintf(target_bits, "%s/home", jailpath);
 
221
 
 
222
        checked_mount(source_bits, target_bits, NULL, MS_BIND, NULL);
 
223
 
 
224
        sprintf(source_bits, "%s/tmp", jailsrc);
 
225
        sprintf(target_bits, "%s/tmp", jailpath);
 
226
 
 
227
        checked_mount(source_bits, target_bits, NULL, MS_BIND, NULL);
 
228
 
 
229
        syslog(LOG_INFO, "mounted %s\n", jailpath);
 
230
 
 
231
        free(jailsrc);
 
232
        free(source_bits);
 
233
        free(target_bits);
 
234
    }
 
235
 
 
236
    free(jaillib);
 
237
}
 
238
#endif /* IVLE_AUFS_JAILS */
 
239
 
 
240
/* Unsets any signal mask applied by the parent process */
 
241
int unmask_signals(void)
 
242
{
 
243
    int result;
 
244
    sigset_t* sigset;
 
245
    sigset = die_if_null(malloc(sizeof(sigset_t)));
 
246
    sigemptyset(sigset);
 
247
    result = sigprocmask(SIG_SETMASK, sigset, NULL);
 
248
    free(sigset);
 
249
    printf("%d", result);
 
250
    return result;
 
251
}
 
252
 
 
253
int main(int argc, char* const argv[])
 
254
{
 
255
    char* jail_base;
 
256
    char* jail_src_base;
 
257
    char* jail_system;
 
258
    char* jailpath;
 
259
    char* work_dir;
 
260
    char* prog;
 
261
    char* const * args;
 
262
    int uid;
 
263
    gid_t groups[1];
 
264
    int arg_num = 1;
 
265
    int daemon_mode = 0;
 
266
    int unlimited = 0;
 
267
    char canonical_jailpath[PATH_MAX];
 
268
 
 
269
    /* Disallow execution from all users but the whitelisted ones, and root */
 
270
    if (!uid_allowed(getuid()))
 
271
    {
 
272
        fprintf(stderr, "only the web server may execute trampoline\n");
 
273
        exit(1);
 
274
    }
 
275
 
 
276
    /* Args check and usage */
 
277
    if (argc < 5)
 
278
    {
 
279
        usage(argv[0]);
 
280
    }
 
281
 
 
282
    if (strcmp(argv[arg_num], "-d") == 0)
 
283
    {
 
284
        if (argc < 6)
 
285
        {
 
286
            usage(argv[0]);
 
287
        }
 
288
        daemon_mode = 1;
 
289
        arg_num++;
 
290
    }
 
291
 
 
292
    if (strcmp(argv[arg_num], "-u") == 0)
 
293
    {
 
294
        if (argc < 6)
 
295
        {
 
296
            usage(argv[0]);
 
297
        }
 
298
        unlimited = 1;
 
299
        arg_num++;
 
300
    }
 
301
    uid = atoi(argv[arg_num++]);
 
302
    jail_base = argv[arg_num++];
 
303
    jail_src_base = argv[arg_num++];
 
304
    jail_system = argv[arg_num++];
 
305
    jailpath = argv[arg_num++];
 
306
    work_dir = argv[arg_num++];
 
307
    prog = argv[arg_num];
 
308
    args = argv + arg_num;
 
309
 
 
310
    /* Disallow suiding to the root user */
 
311
    if (uid == 0)
 
312
    {
 
313
        fprintf(stderr, "cannot set up a jail as root\n");
 
314
        exit(1);
 
315
    }
 
316
 
 
317
    /* Jail path must be an absolute path,
 
318
     * and it must begin with jail_base.
 
319
     */
 
320
    if (norm(canonical_jailpath, PATH_MAX, jailpath) != 0)
 
321
    {
 
322
        fprintf(stderr, "bad jail path: %s\n", jailpath);
 
323
        exit(1);
 
324
    }
 
325
    if (strncmp(canonical_jailpath, jail_base, strlen(jail_base)))
 
326
    {
 
327
        fprintf(stderr, "bad jail path: %s\n", jailpath);
 
328
        exit(1);
 
329
    }
 
330
 
 
331
    openlog("trampoline", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
 
332
 
 
333
    #ifdef IVLE_AUFS_JAILS
 
334
    mount_if_needed(jail_src_base, jail_base, jail_system, canonical_jailpath);
 
335
    #endif /* IVLE_AUFS_JAILS */
 
336
 
 
337
    /* chroot into the jail.
 
338
     * Henceforth this process, and its children, cannot see anything above
 
339
     * canoncial_jailpath. */
 
340
    if (chroot(canonical_jailpath))
 
341
    {
 
342
        syslog(LOG_ERR, "chroot to %s failed\n", canonical_jailpath);
 
343
 
 
344
        perror("could not chroot");
 
345
        exit(1);
 
346
    }
 
347
 
 
348
    /* chdir into the specified working directory */
 
349
    if (chdir(work_dir))
 
350
    {
 
351
        perror("could not chdir");
 
352
        exit(1);
 
353
    }
 
354
 
 
355
    /* setuid to the given user ID.
 
356
     * Henceforth we will be running as this user instead of root.
 
357
     */
 
358
    if (setgid(uid))
 
359
    {
 
360
        perror("could not setgid");
 
361
        exit(1);
 
362
    }
 
363
    
 
364
    groups[0] = uid;
 
365
    if (setgroups(1, groups))
 
366
    {
 
367
        perror("could not setgroups");
 
368
        exit(1);
 
369
    }
 
370
 
 
371
    if (setuid(uid))
 
372
    {
 
373
        perror("could not setuid");
 
374
        exit(1);
 
375
    }
 
376
 
 
377
    /* set user resource limits */
 
378
    if (!unlimited)
 
379
    {
 
380
        struct rlimit l;
 
381
        /* Process adress space in memory */
 
382
        l.rlim_cur = 448 * 1024 * 1024; /* 512MiB - 64MiB */
 
383
        l.rlim_max = 512 * 1024 * 1024; /* 512MiB */
 
384
        if (setrlimit(RLIMIT_AS, &l))
 
385
        {
 
386
            perror("could not setrlimit/RLIMIT_AS");
 
387
            exit(1);
 
388
        }
 
389
        
 
390
        /* Process data segment in memory
 
391
         * Note: This requires a kernel patch to work correctly otherwise it is  
 
392
         * ineffective (thus you are only limited by RLIMIT_AS)
 
393
         */
 
394
        l.rlim_cur = 448 * 1024 * 1024; /* 512MiB - 64MiB */
 
395
        l.rlim_max = 512 * 1024 * 1024; /* 512MiB */
 
396
        if (setrlimit(RLIMIT_DATA, &l))
 
397
        {
 
398
            perror("could not setrlimit/RLIMIT_DATA");
 
399
            exit(1);
 
400
        }
 
401
 
 
402
        /* Core */
 
403
        l.rlim_cur = 0; /* No core files */
 
404
        l.rlim_max = 0; /* No core files */
 
405
        if (setrlimit(RLIMIT_CORE, &l))
 
406
        {
 
407
            perror("could not setrlimit/RLIMIT_CORE");
 
408
            exit(1);
 
409
        }
 
410
 
 
411
        /* CPU */
 
412
        l.rlim_cur = 25; /* 25 Seconds */
 
413
        l.rlim_max = 30; /* 30 Seconds */
 
414
        if (setrlimit(RLIMIT_CPU, &l))
 
415
        {
 
416
            perror("could not setrlimit/RLIMIT_CPU");
 
417
            exit(1);
 
418
        }
 
419
 
 
420
        /* File Size */
 
421
        l.rlim_cur = 64 * 1024 * 1024; /* 64MiB */
 
422
        l.rlim_max = 72 * 1024 * 1024; /* 72MiB */
 
423
        if (setrlimit(RLIMIT_FSIZE, &l))
 
424
        {
 
425
            perror("could not setrlimit/RLIMIT_FSIZE");
 
426
            exit(1);
 
427
        }
 
428
        
 
429
        /* Number of Processes */
 
430
        l.rlim_cur = 50;
 
431
        l.rlim_max = 50;
 
432
        if (setrlimit(RLIMIT_NPROC, &l))
 
433
        {
 
434
            perror("could not setrlimit/RLIMIT_NPROC");
 
435
            exit(1);
 
436
        }
 
437
    }
 
438
 
 
439
    /* Remove any signal handler masks so we can send signals to the child */
 
440
    if(unmask_signals())
 
441
    {
 
442
        perror("could not unmask signals");
 
443
        exit(1);
 
444
    }
 
445
 
 
446
    /* If everything was OK daemonize (if required) */
 
447
    if (daemon_mode)
 
448
    {
 
449
        daemonize();
 
450
    }
 
451
 
 
452
    /* exec (replace this process with the a new instance of the target
 
453
     * program). Pass along all the arguments.
 
454
     * Note that for script execution, the "program" will be the interpreter,
 
455
     * and the first argument will be the script. */
 
456
    execv(prog, args);
 
457
 
 
458
    /* nb exec won't return unless there was an error */
 
459
    syslog(LOG_ERR, "exec of %s in %s failed", prog, canonical_jailpath);
 
460
 
 
461
    perror("could not exec");
 
462
    closelog();
 
463
    return 1;
 
464
}