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

« back to all changes in this revision

Viewing changes to trampoline/trampoline.c

  • Committer: mattgiuca
  • Date: 2008-01-10 00:10:11 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:149
fileservice:
    * Both subversion and OS mode listings now output "." as one of the files.
        This is deliberate in order for the client to see (by the presence or
        absence of the "svnstatus" attribute) whether this directory is
        under version control.
    * Directories no longer display a "type" attribute (since this was always
        just the default type, it's meaningless).
    * Fixed bug where unversioned directories inside a versioned directory
        output an empty listing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
#include <stdlib.h>
38
38
#include <string.h>
39
39
#include <unistd.h>
40
 
#include <syslog.h>
41
 
#include <sys/mount.h>
42
 
#include <sys/types.h>
43
 
#include <sys/stat.h>
44
 
#include <sys/time.h>
45
 
#include <sys/resource.h>
46
 
#include <limits.h>
47
40
 
48
41
/* conf.h is admin-configured by the setup process.
49
42
 * It defines jail_base.
50
43
 */
51
44
#include "conf.h"
52
45
 
53
 
#include "norm.h"
 
46
/* Argument names */
 
47
#define ARG_UID         1
 
48
#define ARG_JAILPATH    2
 
49
#define ARG_CWD         3
 
50
#define ARG_PROG        4
 
51
 
 
52
#define MIN_ARGC        5
 
53
 
 
54
#define UID_ROOT        0
54
55
 
55
56
/* Returns TRUE if the given uid is allowed to execute trampoline.
56
57
 * Only root or the web server should be allowed to execute.
72
73
    return 0;
73
74
}
74
75
 
75
 
/* Turn the process into a daemon using the standard
76
 
 * 2-fork technique.
77
 
 */
78
 
void daemonize(void)
79
 
{
80
 
    pid_t pid, sid;
81
 
 
82
 
    /* already a daemon */
83
 
    if ( getppid() == 1 ) return;
84
 
 
85
 
    /* Fork off the parent process */
86
 
    pid = fork();
87
 
    if (pid < 0) {
88
 
        exit(1);
89
 
    }
90
 
    /* If we got a good PID, then we can exit the parent process. */
91
 
    if (pid > 0) {
92
 
        exit(0);
93
 
    }
94
 
 
95
 
    /* At this point we are executing as the child process */
96
 
 
97
 
    /* Change the file mode mask */
98
 
    umask(022);
99
 
 
100
 
    /* Create a new SID for the child process */
101
 
    sid = setsid();
102
 
    if (sid < 0) {
103
 
        exit(1);
104
 
    }
105
 
 
106
 
    /* Change the current working directory.  This prevents the current
107
 
       directory from being locked; hence not being able to remove it. */
108
 
    if ((chdir("/")) < 0) {
109
 
        exit(1);
110
 
    }
111
 
 
112
 
    /* Redirect standard files to /dev/null */
113
 
    freopen( "/dev/null", "r", stdin);
114
 
    freopen( "/dev/null", "w", stdout);
115
 
    freopen( "/dev/null", "w", stderr);
116
 
}
117
 
 
118
 
static void usage(const char* nm)
119
 
{
120
 
    fprintf(stderr,
121
 
        "usage: %s [-d] [-u] <uid> <jail> <cwd> <program> [args...]\n", nm);
122
 
    exit(1);
123
 
}
124
 
 
125
 
#ifdef IVLE_AUFS_JAILS
126
 
/* Die more pleasantly if mallocs fail. */
127
 
void *die_if_null(void *ptr)
128
 
{
129
 
    if (ptr == NULL)
130
 
    {
131
 
        perror("not enough memory");
132
 
        exit(1);
133
 
    }
134
 
    return ptr;
135
 
}
136
 
 
137
 
/* Find the path of the user components of a jail, given a mountpoint. */
138
 
char *jail_src(const char* jailpath)
139
 
{
140
 
    char* src;
141
 
    int srclen;
142
 
    int dstlen;
143
 
 
144
 
    srclen = strlen(jail_src_base);
145
 
    dstlen = strlen(jail_base);
146
 
    
147
 
    src = die_if_null(malloc(strlen(jailpath) + (srclen - dstlen) + 1));
148
 
    strcpy(src, jail_src_base);
149
 
    strcat(src, jailpath+dstlen);
150
 
 
151
 
    return src;
152
 
}
153
 
 
154
 
/* Check for the validity of a jail in the given path, mounting it if it looks
155
 
 * empty.
156
 
 * TODO: Updating /etc/mtab would be nice. */
157
 
void mount_if_needed(const char* jailpath)
158
 
{
159
 
    char *jailsrc;
160
 
    char *jaillib;
161
 
    char *mountdata;
162
 
 
163
 
    /* Check if there is something useful in the jail. If not, it's probably
164
 
     * not mounted. */
165
 
    jaillib = die_if_null(malloc(strlen(jailpath) + 5));
166
 
    sprintf(jaillib, "%s/lib", jailpath);
167
 
 
168
 
    if (access(jaillib, F_OK))
169
 
    {
170
 
        /* No /lib? Mustn't be mounted. Mount it, creating the dir if needed. */
171
 
        if (access(jailpath, F_OK))
172
 
        {
173
 
             if(mkdir(jailpath, 0755))
174
 
             {
175
 
                 syslog(LOG_ERR, "could not create mountpoint %s\n", jailpath);
176
 
                 perror("could not create jail mountpoint");
177
 
                 exit(1);
178
 
             }
179
 
             syslog(LOG_NOTICE, "created mountpoint %s\n", jailpath);
180
 
        }
181
 
       
182
 
        jailsrc = jail_src(jailpath);
183
 
        mountdata = die_if_null(malloc(3 + strlen(jailsrc) + 4 + strlen(jail_system) + 3 + 1));
184
 
        sprintf(mountdata, "br:%s=rw:%s=ro", jailsrc, jail_system);
185
 
        if (mount("none", jailpath, "aufs", 0, mountdata))
186
 
        {
187
 
            syslog(LOG_ERR, "could not mount %s\n", jailpath);
188
 
            perror("could not mount");
189
 
            exit(1);
190
 
        } 
191
 
 
192
 
        syslog(LOG_INFO, "mounted %s\n", jailpath);
193
 
 
194
 
        free(jailsrc);
195
 
        free(mountdata);
196
 
    }
197
 
 
198
 
    free(jaillib);
199
 
}
200
 
#endif /* IVLE_AUFS_JAILS */
201
 
 
202
76
int main(int argc, char* const argv[])
203
77
{
204
78
    char* jailpath;
205
 
    char* work_dir;
206
 
    char* prog;
207
 
    char* const * args;
208
79
    int uid;
209
 
    int arg_num = 1;
210
 
    int daemon_mode = 0;
211
 
    int unlimited = 0;
212
 
    char canonical_jailpath[PATH_MAX];
213
80
 
214
81
    /* Disallow execution from all users but the whitelisted ones, and root */
215
82
    if (!uid_allowed(getuid()))
219
86
    }
220
87
 
221
88
    /* Args check and usage */
222
 
    if (argc < 5)
223
 
    {
224
 
        usage(argv[0]);
225
 
    }
226
 
 
227
 
    if (strcmp(argv[arg_num], "-d") == 0)
228
 
    {
229
 
        if (argc < 6)
230
 
        {
231
 
            usage(argv[0]);
232
 
        }
233
 
        daemon_mode = 1;
234
 
        arg_num++;
235
 
    }
236
 
 
237
 
    if (strcmp(argv[arg_num], "-u") == 0)
238
 
    {
239
 
        if (argc < 6)
240
 
        {
241
 
            usage(argv[0]);
242
 
        }
243
 
        unlimited = 1;
244
 
        arg_num++;
245
 
    }
246
 
    uid = atoi(argv[arg_num++]);
247
 
    jailpath = argv[arg_num++];
248
 
    work_dir = argv[arg_num++];
249
 
    prog = argv[arg_num];
250
 
    args = argv + arg_num;
 
89
    if (argc < MIN_ARGC)
 
90
    {
 
91
        fprintf(stderr, "usage: %s <uid> <jail> <cwd> <program> [args...]\n",
 
92
            argv[0]);
 
93
        exit(EXIT_FAILURE);
 
94
    }
251
95
 
252
96
    /* Disallow suiding to the root user */
253
 
    if (uid == 0)
 
97
    uid = atoi(argv[ARG_UID]);
 
98
    if (uid == UID_ROOT)
254
99
    {
255
100
        fprintf(stderr, "cannot set up a jail as root\n");
256
101
        exit(1);
257
102
    }
258
103
 
259
 
    /* Jail path must be an absolute path,
260
 
     * and it must begin with jail_base.
 
104
    /* Jail path must:
 
105
     * Be non-empty
 
106
     * Start with a '/'
 
107
     * Not contain "/.."
 
108
     * Begin with jail_base
261
109
     */
262
 
    if (norm(canonical_jailpath, PATH_MAX, jailpath) != 0)
263
 
    {
264
 
        fprintf(stderr, "bad jail path: %s\n", jailpath);
265
 
        exit(1);
266
 
    }
267
 
    if (strncmp(canonical_jailpath, jail_base, strlen(jail_base)))
268
 
    {
269
 
        fprintf(stderr, "bad jail path: %s\n", jailpath);
270
 
        exit(1);
271
 
    }
272
 
 
273
 
    openlog("trampoline", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER);
274
 
 
275
 
    #ifdef IVLE_AUFS_JAILS
276
 
    mount_if_needed(canonical_jailpath);
277
 
    #endif /* IVLE_AUFS_JAILS */
 
110
    jailpath = argv[ARG_JAILPATH];
 
111
    if (strlen(jailpath) < 1 || jailpath[0] != '/'
 
112
            || strstr(jailpath, "/..")
 
113
            || strncmp(jailpath, jail_base, strlen(jail_base)))
 
114
    {
 
115
        fprintf(stderr, "bad jail path: %s\n", jailpath);
 
116
        exit(1);
 
117
    }
278
118
 
279
119
    /* chroot into the jail.
280
120
     * Henceforth this process, and its children, cannot see anything above
281
 
     * canoncial_jailpath. */
282
 
    if (chroot(canonical_jailpath))
 
121
     * jailpath. */
 
122
    if (chroot(jailpath))
283
123
    {
284
 
        syslog(LOG_ERR, "chroot to %s failed\n", canonical_jailpath);
285
 
 
286
124
        perror("could not chroot");
287
125
        exit(1);
288
126
    }
289
127
 
290
128
    /* chdir into the specified working directory */
291
 
    if (chdir(work_dir))
 
129
    if (chdir(argv[ARG_CWD]))
292
130
    {
293
131
        perror("could not chdir");
294
132
        exit(1);
297
135
    /* setuid to the given user ID.
298
136
     * Henceforth we will be running as this user instead of root.
299
137
     */
300
 
    if (setgid(uid))
301
 
    {
302
 
        perror("could not setgid");
303
 
        exit(1);
304
 
    }
305
 
 
306
138
    if (setuid(uid))
307
139
    {
308
140
        perror("could not setuid");
309
141
        exit(1);
310
142
    }
311
143
 
312
 
    if (daemon_mode)
313
 
    {
314
 
        daemonize();
315
 
    }
316
 
 
317
 
    /* set user resource limits */
318
 
    if (!unlimited)
319
 
    {
320
 
        struct rlimit l;
321
 
        /* Process size in virtual memory */
322
 
        l.rlim_cur = 64 * 1024 * 1024; /* 64Mb */
323
 
        l.rlim_max = 72 * 1024 * 1024; /* 64Mb */
324
 
        if (setrlimit(RLIMIT_CORE, &l))
325
 
        {
326
 
            perror("could not setrlimit/RLIMIT_CORE");
327
 
            exit(1);
328
 
        }
329
 
 
330
 
        /* Core */
331
 
        l.rlim_cur = 0;
332
 
        l.rlim_max = 0;
333
 
        if (setrlimit(RLIMIT_CORE, &l))
334
 
        {
335
 
            perror("could not setrlimit/RLIMIT_CORE");
336
 
            exit(1);
337
 
        }
338
 
 
339
 
        /* CPU */
340
 
        l.rlim_cur = 25;
341
 
        l.rlim_max = 30;
342
 
        if (setrlimit(RLIMIT_CPU, &l))
343
 
        {
344
 
            perror("could not setrlimit/RLIMIT_CPU");
345
 
            exit(1);
346
 
        }
347
 
 
348
 
        /* File Size */
349
 
        l.rlim_cur = 64 * 1024 * 1024; /* 64Mb */
350
 
        l.rlim_max = 72 * 1024 * 1024; /* 72Mb */
351
 
        if (setrlimit(RLIMIT_FSIZE, &l))
352
 
        {
353
 
            perror("could not setrlimit/RLIMIT_FSIZE");
354
 
            exit(1);
355
 
        }
356
 
    }
357
 
 
358
144
    /* exec (replace this process with the a new instance of the target
359
145
     * program). Pass along all the arguments.
360
146
     * Note that for script execution, the "program" will be the interpreter,
361
147
     * and the first argument will be the script. */
362
 
    execv(prog, args);
 
148
    execv(argv[ARG_PROG], argv + ARG_PROG);
363
149
 
364
150
    /* nb exec won't return unless there was an error */
365
 
    syslog(LOG_ERR, "exec of %s in %s failed", prog, canonical_jailpath);
366
 
 
367
151
    perror("could not exec");
368
 
    closelog();
369
 
    return 1;
 
152
    return EXIT_FAILURE;
370
153
}