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

« back to all changes in this revision

Viewing changes to trampoline/trampoline.c

  • Committer: dcoles
  • Date: 2008-07-03 04:20:54 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:803
Setup: Modularised setup.py so it is now no longer over 1000 lines. This should 
allow us to get in there and tidy up each module much easier. Also removed 
updatejails since this functionality seems to be duplicated with remakeuser.py 
and remakealluser.py scripts.

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 scripts.
 
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
 * Usage: trampoline uid jail-path working-path program [args...]
 
31
 * Must run as root. Will safely setuid to the supplied uid, checking that it
 
32
 * is not root. Recommended that the file is set up as follows:
 
33
 *  sudo chown root:root trampoline; sudo chroot +s trampoline
 
34
 */
 
35
 
 
36
#include <stdio.h>
 
37
#include <stdlib.h>
 
38
#include <string.h>
 
39
#include <unistd.h>
 
40
#include <sys/types.h>
 
41
#include <sys/stat.h>
 
42
#include <sys/time.h>
 
43
#include <sys/resource.h>
 
44
#include <limits.h>
 
45
 
 
46
/* conf.h is admin-configured by the setup process.
 
47
 * It defines jail_base.
 
48
 */
 
49
#include "conf.h"
 
50
 
 
51
/* Returns TRUE if the given uid is allowed to execute trampoline.
 
52
 * Only root or the web server should be allowed to execute.
 
53
 * This is determined by the whitelist allowed_uids in conf.h.
 
54
 */
 
55
int uid_allowed(int uid)
 
56
{
 
57
    int i;
 
58
    /* root is always allowed to execute trampoline */
 
59
    if (uid == 0)
 
60
        return 1;
 
61
    /* loop over all allowed_uids */
 
62
    for (i=(sizeof(allowed_uids)/sizeof(*allowed_uids))-1; i>=0; i--)
 
63
    {
 
64
        if (allowed_uids[i] == uid)
 
65
            return 1;
 
66
    }
 
67
    /* default to disallowing */
 
68
    return 0;
 
69
}
 
70
 
 
71
/* Turn the process into a daemon using the standard
 
72
 * 2-fork technique.
 
73
 */
 
74
void daemonize(void)
 
75
{
 
76
    pid_t pid, sid;
 
77
 
 
78
    /* already a daemon */
 
79
    if ( getppid() == 1 ) return;
 
80
 
 
81
    /* Fork off the parent process */
 
82
    pid = fork();
 
83
    if (pid < 0) {
 
84
        exit(1);
 
85
    }
 
86
    /* If we got a good PID, then we can exit the parent process. */
 
87
    if (pid > 0) {
 
88
        exit(0);
 
89
    }
 
90
 
 
91
    /* At this point we are executing as the child process */
 
92
 
 
93
    /* Change the file mode mask */
 
94
    umask(022);
 
95
 
 
96
    /* Create a new SID for the child process */
 
97
    sid = setsid();
 
98
    if (sid < 0) {
 
99
        exit(1);
 
100
    }
 
101
 
 
102
    /* Change the current working directory.  This prevents the current
 
103
       directory from being locked; hence not being able to remove it. */
 
104
    if ((chdir("/")) < 0) {
 
105
        exit(1);
 
106
    }
 
107
 
 
108
    /* Redirect standard files to /dev/null */
 
109
    freopen( "/dev/null", "r", stdin);
 
110
    freopen( "/dev/null", "w", stdout);
 
111
    freopen( "/dev/null", "w", stderr);
 
112
}
 
113
 
 
114
static void usage(const char* nm)
 
115
{
 
116
    fprintf(stderr,
 
117
        "usage: %s [-d] [-u] <uid> <jail> <cwd> <program> [args...]\n", nm);
 
118
    exit(1);
 
119
}
 
120
 
 
121
int main(int argc, char* const argv[])
 
122
{
 
123
    char* jailpath;
 
124
    char* work_dir;
 
125
    char* prog;
 
126
    char* const * args;
 
127
    int uid;
 
128
    int arg_num = 1;
 
129
    int daemon_mode = 0;
 
130
    int unlimited = 0;
 
131
    char canonical_jailpath[PATH_MAX];
 
132
 
 
133
    /* Disallow execution from all users but the whitelisted ones, and root */
 
134
    if (!uid_allowed(getuid()))
 
135
    {
 
136
        fprintf(stderr, "only the web server may execute trampoline\n");
 
137
        exit(1);
 
138
    }
 
139
 
 
140
    /* Args check and usage */
 
141
    if (argc < 5)
 
142
    {
 
143
        usage(argv[0]);
 
144
    }
 
145
 
 
146
    if (strcmp(argv[arg_num], "-d") == 0)
 
147
    {
 
148
        if (argc < 6)
 
149
        {
 
150
            usage(argv[0]);
 
151
        }
 
152
        daemon_mode = 1;
 
153
        arg_num++;
 
154
    }
 
155
 
 
156
    if (strcmp(argv[arg_num], "-u") == 0)
 
157
    {
 
158
        if (argc < 6)
 
159
        {
 
160
            usage(argv[0]);
 
161
        }
 
162
        unlimited = 1;
 
163
        arg_num++;
 
164
    }
 
165
    uid = atoi(argv[arg_num++]);
 
166
    jailpath = argv[arg_num++];
 
167
    work_dir = argv[arg_num++];
 
168
    prog = argv[arg_num];
 
169
    args = argv + arg_num;
 
170
 
 
171
    /* Disallow suiding to the root user */
 
172
    if (uid == 0)
 
173
    {
 
174
        fprintf(stderr, "cannot set up a jail as root\n");
 
175
        exit(1);
 
176
    }
 
177
 
 
178
    /* Jail path must be an absolute path,
 
179
     * and it must begin with jail_base.
 
180
     */
 
181
    if (norm(canonical_jailpath, PATH_MAX, jailpath) != 0)
 
182
    {
 
183
        fprintf(stderr, "bad jail path: %s\n", jailpath);
 
184
        exit(1);
 
185
    }
 
186
    if (strncmp(canonical_jailpath, jail_base, strlen(jail_base)))
 
187
    {
 
188
        fprintf(stderr, "bad jail path: %s\n", jailpath);
 
189
        exit(1);
 
190
    }
 
191
 
 
192
    /* chroot into the jail.
 
193
     * Henceforth this process, and its children, cannot see anything above
 
194
     * canoncial_jailpath. */
 
195
    if (chroot(canonical_jailpath))
 
196
    {
 
197
        perror("could not chroot");
 
198
        exit(1);
 
199
    }
 
200
 
 
201
    /* chdir into the specified working directory */
 
202
    if (chdir(work_dir))
 
203
    {
 
204
        perror("could not chdir");
 
205
        exit(1);
 
206
    }
 
207
 
 
208
    /* setuid to the given user ID.
 
209
     * Henceforth we will be running as this user instead of root.
 
210
     */
 
211
    if (setgid(uid))
 
212
    {
 
213
        perror("could not setgid");
 
214
        exit(1);
 
215
    }
 
216
 
 
217
    if (setuid(uid))
 
218
    {
 
219
        perror("could not setuid");
 
220
        exit(1);
 
221
    }
 
222
 
 
223
    if (daemon_mode)
 
224
    {
 
225
        daemonize();
 
226
    }
 
227
 
 
228
    /* set user resource limits */
 
229
    if (!unlimited)
 
230
    {
 
231
        struct rlimit l;
 
232
        /* Process size in virtual memory */
 
233
        l.rlim_cur = 64 * 1024 * 1024; /* 64Mb */
 
234
        l.rlim_max = 72 * 1024 * 1024; /* 64Mb */
 
235
        if (setrlimit(RLIMIT_AS, &l))
 
236
        {
 
237
            perror("could not setrlimit/RLIMIT_AS");
 
238
            exit(1);
 
239
        }
 
240
 
 
241
        /* Core */
 
242
        l.rlim_cur = 0;
 
243
        l.rlim_max = 0;
 
244
        if (setrlimit(RLIMIT_CORE, &l))
 
245
        {
 
246
            perror("could not setrlimit/RLIMIT_CORE");
 
247
            exit(1);
 
248
        }
 
249
 
 
250
        /* CPU */
 
251
        l.rlim_cur = 25;
 
252
        l.rlim_max = 30;
 
253
        if (setrlimit(RLIMIT_CPU, &l))
 
254
        {
 
255
            perror("could not setrlimit/RLIMIT_CPU");
 
256
            exit(1);
 
257
        }
 
258
 
 
259
        /* File Size */
 
260
        l.rlim_cur = 64 * 1024 * 1024; /* 64Mb */
 
261
        l.rlim_max = 72 * 1024 * 1024; /* 72Mb */
 
262
        if (setrlimit(RLIMIT_FSIZE, &l))
 
263
        {
 
264
            perror("could not setrlimit/RLIMIT_FSIZE");
 
265
            exit(1);
 
266
        }
 
267
    }
 
268
 
 
269
    /* exec (replace this process with the a new instance of the target
 
270
     * program). Pass along all the arguments.
 
271
     * Note that for script execution, the "program" will be the interpreter,
 
272
     * and the first argument will be the script. */
 
273
    execv(prog, args);
 
274
 
 
275
    /* XXX if (daemon_mode) use syslog? */
 
276
    /* nb exec won't return unless there was an error */
 
277
    perror("could not exec");
 
278
    return 1;
 
279
}