~ubuntu-branches/ubuntu/natty/sudo/natty

« back to all changes in this revision

Viewing changes to selinux.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2008-06-18 11:41:27 UTC
  • mfrom: (1.2.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20080618114127-8gov9f4vxfzlr0qr
Tags: 1.6.9p15-2ubuntu1
* Merge from debian unstable, remaining changes:
 - logging.c: Ignore SIGPIPE when creating an error email, so that non-fatal
   error messages (like "unable to resolve local host name") do not lead to
   being killed with SIGPIPE if /usr/bin/sendmail does not exist or crashes.
   (LP #32906, http://www.gratisoft.us/bugzilla/show_bug.cgi?id=285)
 - debian/postinst: put "NOPASSWD" example at the bottom, so that
   uncommenting it will actually work (later entries override former ones).
   (LP #131399, Debian #479616)
 - debian/rules: Disable lecture, enable tty_tickets by default. (Ubuntu
   specific)
 - Add debian/sudo_root.8: Explanation of root handling through sudo.
   Install it in debian/rules. (Ubuntu specific)
 - sudo.c: If the user successfully authenticated and he is in the 'admin'
   group, then create a stamp ~/.sudo_as_admin_successful. Our default bash
   profile checks for this and displays a short intro about sudo if the
   flag is not present. (Ubuntu specific)
 - env.c: Add "http_proxy" to initial_keepenv_table, so that it is kept
   for "sudo apt-get ...". (Ubuntu specific EBW hack, should disappear at
   some point)
* debian/{rules,postinst}: Disable init script installation. Debian
  reintroduced it because /var/run tmpfs is not the default there, but has
  been on Ubuntu for ages.

Show diffs side-by-side

added added

removed removed

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