~ubuntu-branches/ubuntu/quantal/sudo/quantal

« back to all changes in this revision

Viewing changes to selinux.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2011-11-20 12:07:45 UTC
  • mfrom: (1.3.17 sid)
  • Revision ID: package-import@ubuntu.com-20111120120745-o3qpklobmygytndc
Tags: 1.8.3p1-1ubuntu1
* Merge from debian/testing, remaining changes:
  - debian/patches/keep_home_by_default.patch:
    + Set HOME in initial_keepenv_table. (rebased for 1.8.3p1)
  - debian/patches/enable_badpass.patch: turn on "mail_badpass" by default:
    + attempting sudo without knowing a login password is as bad as not
      being listed in the sudoers file, especially if getting the password
      wrong means doing the access-check-email-notification never happens
      (rebased for 1.8.3p1)
  - debian/rules:
    + compile with --without-lecture --with-tty-tickets (Ubuntu specific)
    + install man/man8/sudo_root.8 (Ubuntu specific)
    + install apport hooks
    + The ubuntu-sudo-as-admin-successful.patch was taken upstream by
      Debian however it requires a --enable-admin-flag configure flag to
      actually enable it.
  - debian/sudoers: 
    + grant admin group sudo access
  - debian/sudo-ldap.dirs, debian/sudo.dirs: 
    + add usr/share/apport/package-hooks
  - debian/sudo.preinst:
    + avoid conffile prompt by checking for known default /etc/sudoers
      and if found installing the correct default /etc/sudoers file

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
3
 
 * Copyright (c) 2008 Dan Walsh <dwalsh@redhat.com>
4
 
 *
5
 
 * Borrowed heavily from newrole source code
6
 
 * Authors:
7
 
 *      Anthony Colatrella
8
 
 *      Tim Fraser
9
 
 *      Steve Grubb <sgrubb@redhat.com>
10
 
 *      Darrel Goeddel <DGoeddel@trustedcs.com>
11
 
 *      Michael Thompson <mcthomps@us.ibm.com>
12
 
 *      Dan Walsh <dwalsh@redhat.com>
13
 
 *
14
 
 * Permission to use, copy, modify, and distribute this software for any
15
 
 * purpose with or without fee is hereby granted, provided that the above
16
 
 * copyright notice and this permission notice appear in all copies.
17
 
 *
18
 
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
19
 
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
20
 
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
21
 
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22
 
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
23
 
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
24
 
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25
 
 */
26
 
 
27
 
#include <config.h>
28
 
 
29
 
#include <sys/types.h>
30
 
#include <sys/wait.h>
31
 
#include <stdio.h>
32
 
#include <stdlib.h>
33
 
#include <stddef.h>
34
 
#include <string.h>
35
 
#include <unistd.h>
36
 
#include <errno.h>
37
 
#include <fcntl.h>
38
 
#include <signal.h>
39
 
#ifdef HAVE_LINUX_AUDIT
40
 
#include <libaudit.h>
41
 
#endif
42
 
 
43
 
#include <selinux/flask.h>             /* for SECCLASS_CHR_FILE */
44
 
#include <selinux/selinux.h>           /* for is_selinux_enabled() */
45
 
#include <selinux/context.h>           /* for context-mangling functions */
46
 
#include <selinux/get_default_type.h>
47
 
#include <selinux/get_context_list.h>
48
 
 
49
 
#include "sudo.h"
50
 
#include "linux_audit.h"
51
 
 
52
 
static struct selinux_state {
53
 
    security_context_t old_context;
54
 
    security_context_t new_context;
55
 
    security_context_t tty_context;
56
 
    security_context_t new_tty_context;
57
 
    const char *ttyn;
58
 
    int ttyfd;
59
 
    int enforcing;
60
 
} se_state;
61
 
 
62
 
/*
63
 
 * This function attempts to revert the relabeling done to the tty.
64
 
 * fd              - referencing the opened ttyn
65
 
 * ttyn            - name of tty to restore
66
 
 *
67
 
 * Returns zero on success, non-zero otherwise
68
 
 */
69
 
int
70
 
selinux_restore_tty(void)
71
 
{
72
 
    int retval = 0;
73
 
    security_context_t chk_tty_context = NULL;
74
 
 
75
 
    if (se_state.ttyfd == -1 || se_state.new_tty_context == NULL)
76
 
        goto skip_relabel;
77
 
 
78
 
    /* Verify that the tty still has the context set by sudo. */
79
 
    if ((retval = fgetfilecon(se_state.ttyfd, &chk_tty_context)) < 0) {
80
 
        warning("unable to fgetfilecon %s", se_state.ttyn);
81
 
        goto skip_relabel;
82
 
    }
83
 
 
84
 
    if ((retval = strcmp(chk_tty_context, se_state.new_tty_context))) {
85
 
        warningx("%s changed labels.", se_state.ttyn);
86
 
        goto skip_relabel;
87
 
    }
88
 
 
89
 
    if ((retval = fsetfilecon(se_state.ttyfd, se_state.tty_context)) < 0)
90
 
        warning("unable to restore context for %s", se_state.ttyn);
91
 
 
92
 
skip_relabel:
93
 
    if (se_state.ttyfd != -1) {
94
 
        close(se_state.ttyfd);
95
 
        se_state.ttyfd = -1;
96
 
    }
97
 
    if (chk_tty_context != NULL) {
98
 
        freecon(chk_tty_context);
99
 
        chk_tty_context = NULL;
100
 
    }
101
 
    return retval;
102
 
}
103
 
 
104
 
/*
105
 
 * This function attempts to relabel the tty. If this function fails, then
106
 
 * the contexts are free'd and -1 is returned. On success, 0 is returned
107
 
 * and tty_context and new_tty_context are set.
108
 
 *
109
 
 * This function will not fail if it can not relabel the tty when selinux is
110
 
 * in permissive mode.
111
 
 */
112
 
static int
113
 
relabel_tty(const char *ttyn, int ptyfd)
114
 
{
115
 
    security_context_t tty_con = NULL;
116
 
    security_context_t new_tty_con = NULL;
117
 
    int fd;
118
 
 
119
 
    se_state.ttyfd = ptyfd;
120
 
 
121
 
    /* It is perfectly legal to have no tty. */
122
 
    if (ptyfd == -1 && ttyn == NULL)
123
 
        return 0;
124
 
 
125
 
    /* If sudo is not allocating a pty for the command, open current tty. */
126
 
    if (ptyfd == -1) {
127
 
        se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK);
128
 
        if (se_state.ttyfd == -1) {
129
 
            warning("unable to open %s, not relabeling tty", ttyn);
130
 
            if (se_state.enforcing)
131
 
                goto bad;
132
 
        }
133
 
        (void)fcntl(se_state.ttyfd, F_SETFL,
134
 
            fcntl(se_state.ttyfd, F_GETFL, 0) & ~O_NONBLOCK);
135
 
    }
136
 
 
137
 
    if (fgetfilecon(se_state.ttyfd, &tty_con) < 0) {
138
 
        warning("unable to get current tty context, not relabeling tty");
139
 
        if (se_state.enforcing)
140
 
            goto bad;
141
 
    }
142
 
 
143
 
    if (tty_con && (security_compute_relabel(se_state.new_context, tty_con,
144
 
        SECCLASS_CHR_FILE, &new_tty_con) < 0)) {
145
 
        warning("unable to get new tty context, not relabeling tty");
146
 
        if (se_state.enforcing)
147
 
            goto bad;
148
 
    }
149
 
 
150
 
    if (new_tty_con != NULL) {
151
 
        if (fsetfilecon(se_state.ttyfd, new_tty_con) < 0) {
152
 
            warning("unable to set new tty context");
153
 
            if (se_state.enforcing)
154
 
                goto bad;
155
 
        }
156
 
    }
157
 
 
158
 
    if (ptyfd != -1) {
159
 
        /* Reopen pty that was relabeled, std{in,out,err} are reset later. */
160
 
        se_state.ttyfd = open(ttyn, O_RDWR|O_NOCTTY, 0);
161
 
        if (se_state.ttyfd == -1) {
162
 
            warning("cannot open %s", ttyn);
163
 
            if (se_state.enforcing)
164
 
                goto bad;
165
 
        }
166
 
        if (dup2(se_state.ttyfd, ptyfd) == -1) {
167
 
            warning("dup2");
168
 
            goto bad;
169
 
        }
170
 
    } else {
171
 
        /* Re-open tty to get new label and reset std{in,out,err} */
172
 
        close(se_state.ttyfd);
173
 
        se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK);
174
 
        if (se_state.ttyfd == -1) {
175
 
            warning("unable to open %s", ttyn);
176
 
            goto bad;
177
 
        }
178
 
        (void)fcntl(se_state.ttyfd, F_SETFL,
179
 
            fcntl(se_state.ttyfd, F_GETFL, 0) & ~O_NONBLOCK);
180
 
        for (fd = STDIN_FILENO; fd <= STDERR_FILENO; fd++) {
181
 
            if (isatty(fd) && dup2(se_state.ttyfd, fd) == -1) {
182
 
                warning("dup2");
183
 
                goto bad;
184
 
            }
185
 
        }
186
 
    }
187
 
    /* Retain se_state.ttyfd so we can restore label when command finishes. */
188
 
    (void)fcntl(se_state.ttyfd, F_SETFD, FD_CLOEXEC);
189
 
 
190
 
    se_state.ttyn = ttyn;
191
 
    se_state.tty_context = tty_con;
192
 
    se_state.new_tty_context = new_tty_con;
193
 
    return 0;
194
 
 
195
 
bad:
196
 
    if (se_state.ttyfd != -1 && se_state.ttyfd != ptyfd) {
197
 
        close(se_state.ttyfd);
198
 
        se_state.ttyfd = -1;
199
 
    }
200
 
    freecon(tty_con);
201
 
    return -1;
202
 
}
203
 
 
204
 
/*
205
 
 * Returns a new security context based on the old context and the
206
 
 * specified role and type.
207
 
 */
208
 
security_context_t
209
 
get_exec_context(security_context_t old_context, const char *role, const char *type)
210
 
{
211
 
    security_context_t new_context = NULL;
212
 
    context_t context = NULL;
213
 
    char *typebuf = NULL;
214
 
    
215
 
    /* We must have a role, the type is optional (we can use the default). */
216
 
    if (!role) {
217
 
        warningx("you must specify a role for type %s", type);
218
 
        errno = EINVAL;
219
 
        return NULL;
220
 
    }
221
 
    if (!type) {
222
 
        if (get_default_type(role, &typebuf)) {
223
 
            warningx("unable to get default type for role %s", role);
224
 
            errno = EINVAL;
225
 
            return NULL;
226
 
        }
227
 
        type = typebuf;
228
 
    }
229
 
    
230
 
    /* 
231
 
     * Expand old_context into a context_t so that we extract and modify 
232
 
     * its components easily. 
233
 
     */
234
 
    context = context_new(old_context);
235
 
    
236
 
    /*
237
 
     * Replace the role and type in "context" with the role and
238
 
     * type we will be running the command as.
239
 
     */
240
 
    if (context_role_set(context, role)) {
241
 
        warning("failed to set new role %s", role);
242
 
        goto bad;
243
 
    }
244
 
    if (context_type_set(context, type)) {
245
 
        warning("failed to set new type %s", type);
246
 
        goto bad;
247
 
    }
248
 
      
249
 
    /*
250
 
     * Convert "context" back into a string and verify it.
251
 
     */
252
 
    new_context = estrdup(context_str(context));
253
 
    if (security_check_context(new_context) < 0) {
254
 
        warningx("%s is not a valid context", new_context);
255
 
        errno = EINVAL;
256
 
        goto bad;
257
 
    }
258
 
 
259
 
#ifdef DEBUG
260
 
    warningx("Your new context is %s", new_context);
261
 
#endif
262
 
 
263
 
    context_free(context);
264
 
    return new_context;
265
 
 
266
 
bad:
267
 
    free(typebuf);
268
 
    context_free(context);
269
 
    freecon(new_context);
270
 
    return NULL;
271
 
}
272
 
 
273
 
/* 
274
 
 * Set the exec and tty contexts in preparation for fork/exec.
275
 
 * Must run as root, before the uid change.
276
 
 * If ptyfd is not -1, it indicates we are running
277
 
 * in a pty and do not need to reset std{in,out,err}.
278
 
 * Returns 0 on success and -1 on failure.
279
 
 */
280
 
int
281
 
selinux_setup(const char *role, const char *type, const char *ttyn,
282
 
    int ptyfd)
283
 
{
284
 
    int rval = -1;
285
 
 
286
 
    /* Store the caller's SID in old_context. */
287
 
    if (getprevcon(&se_state.old_context)) {
288
 
        warning("failed to get old_context");
289
 
        goto done;
290
 
    }
291
 
 
292
 
    se_state.enforcing = security_getenforce();
293
 
    if (se_state.enforcing < 0) {
294
 
        warning("unable to determine enforcing mode.");
295
 
        goto done;
296
 
    }
297
 
 
298
 
#ifdef DEBUG
299
 
    warningx("your old context was %s", se_state.old_context);
300
 
#endif
301
 
    se_state.new_context = get_exec_context(se_state.old_context, role, type);
302
 
    if (!se_state.new_context)
303
 
        goto done;
304
 
    
305
 
    if (relabel_tty(ttyn, ptyfd) < 0) {
306
 
        warning("unable to setup tty context for %s", se_state.new_context);
307
 
        goto done;
308
 
    }
309
 
 
310
 
#ifdef DEBUG
311
 
    if (se_state.ttyfd != -1) {
312
 
        warningx("your old tty context is %s", se_state.tty_context);
313
 
        warningx("your new tty context is %s", se_state.new_tty_context);
314
 
    }
315
 
#endif
316
 
 
317
 
#ifdef HAVE_LINUX_AUDIT
318
 
    linux_audit_role_change(se_state.old_context, se_state.new_context,
319
 
        se_state.ttyn);
320
 
#endif
321
 
 
322
 
    rval = 0;
323
 
 
324
 
done:
325
 
    return rval;
326
 
}
327
 
 
328
 
void
329
 
selinux_execve(const char *path, char *argv[], char *envp[])
330
 
{
331
 
    if (setexeccon(se_state.new_context)) {
332
 
        warning("unable to set exec context to %s", se_state.new_context);
333
 
        if (se_state.enforcing)
334
 
            return;
335
 
    }
336
 
 
337
 
#ifdef HAVE_SETKEYCREATECON
338
 
    if (setkeycreatecon(se_state.new_context)) {
339
 
        warning("unable to set key creation context to %s", se_state.new_context);
340
 
        if (se_state.enforcing)
341
 
            return;
342
 
    }
343
 
#endif /* HAVE_SETKEYCREATECON */
344
 
 
345
 
    /* We use the "spare" slot in argv to store sesh. */
346
 
    --argv;
347
 
    argv[0] = *argv[1] == '-' ? "-sesh" : "sesh";
348
 
    argv[1] = (char *)path;
349
 
 
350
 
    execve(_PATH_SUDO_SESH, argv, envp);
351
 
}