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

1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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
1305 by David Coles
Trampoline will now also set the groups of a user as well as the uid and gid.
36
#define _BSD_SOURCE
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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>
1305 by David Coles
Trampoline will now also set the groups of a user as well as the uid and gid.
48
#include <grp.h>
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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,
1092.1.49 by William Grant
trampoline now takes the jail paths in argv.
125
        "usage: %s [-d] [-u] <uid> <base> <src> <system> <jail> <cwd> <program> [args...]\n", nm);
1304 by David Coles
Fix up the documentation of trampoline you don't have to dig in the code to work out how to call it (it's still quite nightmareish)
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");
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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
1281.1.5 by William Grant
Make trampoline mount jails new-style (without AUFS).
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
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
166
/* Find the path of the user components of a jail, given a mountpoint. */
1092.1.49 by William Grant
trampoline now takes the jail paths in argv.
167
char *jail_src(const char *jail_src_base, const char *jail_base,
168
               const char *jailpath)
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
169
{
170
    char* src;
171
    int srclen;
172
    int dstlen;
173
174
    srclen = strlen(jail_src_base);
175
    dstlen = strlen(jail_base);
1281.1.5 by William Grant
Make trampoline mount jails new-style (without AUFS).
176
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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. */
1092.1.49 by William Grant
trampoline now takes the jail paths in argv.
187
void mount_if_needed(const char *jail_src_base, const char *jail_base,
188
                     const char *jail_system, const char *jailpath)
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
189
{
190
    char *jailsrc;
191
    char *jaillib;
1281.1.5 by William Grant
Make trampoline mount jails new-style (without AUFS).
192
    char *source_bits;
193
    char *target_bits;
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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
        }
1281.1.5 by William Grant
Make trampoline mount jails new-style (without AUFS).
213
1092.1.49 by William Grant
trampoline now takes the jail paths in argv.
214
        jailsrc = jail_src(jail_src_base, jail_base, jailpath);
1281.1.5 by William Grant
Make trampoline mount jails new-style (without AUFS).
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);
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
228
229
        syslog(LOG_INFO, "mounted %s\n", jailpath);
230
231
        free(jailsrc);
1281.1.5 by William Grant
Make trampoline mount jails new-style (without AUFS).
232
        free(source_bits);
233
        free(target_bits);
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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
{
1092.1.49 by William Grant
trampoline now takes the jail paths in argv.
255
    char* jail_base;
256
    char* jail_src_base;
257
    char* jail_system;
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
258
    char* jailpath;
259
    char* work_dir;
260
    char* prog;
261
    char* const * args;
262
    int uid;
1305 by David Coles
Trampoline will now also set the groups of a user as well as the uid and gid.
263
    gid_t groups[1];
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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++]);
1092.1.49 by William Grant
trampoline now takes the jail paths in argv.
302
    jail_base = argv[arg_num++];
303
    jail_src_base = argv[arg_num++];
304
    jail_system = argv[arg_num++];
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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
1092.1.49 by William Grant
trampoline now takes the jail paths in argv.
334
    mount_if_needed(jail_src_base, jail_base, jail_system, canonical_jailpath);
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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
    }
1305 by David Coles
Trampoline will now also set the groups of a user as well as the uid and gid.
363
    
364
    groups[0] = uid;
365
    if (setgroups(1, groups))
366
    {
367
        perror("could not setgroups");
368
        exit(1);
369
    }
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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 */
1301 by William Grant
Double trampoline memory limits.
382
        l.rlim_cur = 448 * 1024 * 1024; /* 512MiB - 64MiB */
383
        l.rlim_max = 512 * 1024 * 1024; /* 512MiB */
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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
         */
1301 by William Grant
Double trampoline memory limits.
394
        l.rlim_cur = 448 * 1024 * 1024; /* 512MiB - 64MiB */
395
        l.rlim_max = 512 * 1024 * 1024; /* 512MiB */
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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 */
1303 by David Coles
Add a rather lenient RLIMIT_NPROC that will prevent simple fork bombs (hopefully accidental...) from taking down a server.
423
        if (setrlimit(RLIMIT_FSIZE, &l))
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
424
        {
425
            perror("could not setrlimit/RLIMIT_FSIZE");
426
            exit(1);
427
        }
1303 by David Coles
Add a rather lenient RLIMIT_NPROC that will prevent simple fork bombs (hopefully accidental...) from taking down a server.
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
        }
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
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
}