~vorlon/ubuntu/natty/sudo/keep_home_by_default

« back to all changes in this revision

Viewing changes to sudo_edit.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-05-11 18:07:03 UTC
  • mfrom: (1.1.6 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090511180703-vl2t8cem14g6r61c
Tags: 1.7.0-1ubuntu1
* Merge from debian unstable, remaining changes:
 - 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,sudo-ldap.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
1
/*
2
 
 * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
 
2
 * Copyright (c) 2004-2008 Todd C. Miller <Todd.Miller@courtesan.com>
3
3
 *
4
4
 * Permission to use, copy, modify, and distribute this software for any
5
5
 * purpose with or without fee is hereby granted, provided that the above
41
41
#ifdef HAVE_UNISTD_H
42
42
# include <unistd.h>
43
43
#endif /* HAVE_UNISTD_H */
44
 
#ifdef HAVE_ERR_H
45
 
# include <err.h>
46
 
#else
47
 
# include "emul/err.h"
48
 
#endif /* HAVE_ERR_H */
49
44
#include <ctype.h>
50
45
#include <pwd.h>
51
 
#include <grp.h>
52
46
#include <signal.h>
53
47
#include <errno.h>
54
48
#include <fcntl.h>
62
56
#include "sudo.h"
63
57
 
64
58
#ifndef lint
65
 
__unused static const char rcsid[] = "$Sudo: sudo_edit.c,v 1.6.2.9 2008/06/21 00:47:52 millert Exp $";
 
59
__unused static const char rcsid[] = "$Sudo: sudo_edit.c,v 1.37 2008/11/09 14:13:12 millert Exp $";
66
60
#endif /* lint */
67
61
 
68
62
extern sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
69
63
extern char **environ;
70
64
 
 
65
static char *find_editor();
 
66
 
71
67
/*
72
68
 * Wrapper to allow users to edit privileged files with their own uid.
73
69
 */
74
 
int sudo_edit(argc, argv, envp)
 
70
int
 
71
sudo_edit(argc, argv, envp)
75
72
    int argc;
76
73
    char **argv;
77
74
    char **envp;
82
79
    char **nargv, **ap, *editor, *cp;
83
80
    char buf[BUFSIZ];
84
81
    int error, i, ac, ofd, tfd, nargc, rval, tmplen, wasblank;
85
 
    sigaction_t sa;
86
82
    struct stat sb;
87
83
    struct timespec ts1, ts2;
88
84
    struct tempfile {
108
104
        tmplen--;
109
105
 
110
106
    /*
 
107
     * Close password, shadow, and group files before we try to open
 
108
     * user-specified files to prevent the opening of things like /dev/fd/4
 
109
     */
 
110
    sudo_endpwent();
 
111
    sudo_endgrent();
 
112
 
 
113
    /*
111
114
     * For each file specified by the user, make a temporary version
112
115
     * and copy the contents of the original to it.
113
116
     */
114
117
    tf = emalloc2(argc - 1, sizeof(*tf));
115
 
    memset(tf, 0, (argc - 1) * sizeof(*tf));
 
118
    zero_bytes(tf, (argc - 1) * sizeof(*tf));
116
119
    for (i = 0, ap = argv + 1; i < argc - 1 && *ap != NULL; i++, ap++) {
117
120
        error = -1;
118
121
        set_perms(PERM_RUNAS);
119
 
 
120
 
        /*
121
 
         * We close the password file before we try to open the user-specified
122
 
         * path to prevent the opening of things like /dev/fd/4.
123
 
         */
124
 
        endpwent();
125
122
        if ((ofd = open(*ap, O_RDONLY, 0644)) != -1 || errno == ENOENT) {
126
123
            if (ofd == -1) {
127
 
                memset(&sb, 0, sizeof(sb));             /* new file */
 
124
                zero_bytes(&sb, sizeof(sb));            /* new file */
128
125
                error = 0;
129
126
            } else {
130
127
#ifdef HAVE_FSTAT
137
134
        set_perms(PERM_ROOT);
138
135
        if (error || (ofd != -1 && !S_ISREG(sb.st_mode))) {
139
136
            if (error)
140
 
                warn("%s", *ap);
 
137
                warning("%s", *ap);
141
138
            else
142
 
                warnx("%s: not a regular file", *ap);
 
139
                warningx("%s: not a regular file", *ap);
143
140
            if (ofd != -1)
144
141
                close(ofd);
145
142
            argc--;
159
156
        tfd = mkstemp(tf[i].tfile);
160
157
        set_perms(PERM_ROOT);
161
158
        if (tfd == -1) {
162
 
            warn("mkstemp");
 
159
            warning("mkstemp");
163
160
            goto cleanup;
164
161
        }
165
162
        if (ofd != -1) {
166
163
            while ((nread = read(ofd, buf, sizeof(buf))) != 0) {
167
164
                if ((nwritten = write(tfd, buf, nread)) != nread) {
168
165
                    if (nwritten == -1)
169
 
                        warn("%s", tf[i].tfile);
 
166
                        warning("%s", tf[i].tfile);
170
167
                    else
171
 
                        warnx("%s: short write", tf[i].tfile);
 
168
                        warningx("%s: short write", tf[i].tfile);
172
169
                    goto cleanup;
173
170
                }
174
171
            }
194
191
    if (argc == 1)
195
192
        return(1);                      /* no files readable, you lose */
196
193
 
197
 
    /*
198
 
     * Determine which editor to use.  We don't bother restricting this
199
 
     * based on def_env_editor or def_editor since the editor runs with
200
 
     * the uid of the invoking user, not the runas (privileged) user.
201
 
     */
202
194
    environ = envp;
203
 
    if (((editor = getenv("VISUAL")) != NULL && *editor != '\0') ||
204
 
        ((editor = getenv("EDITOR")) != NULL && *editor != '\0')) {
205
 
        editor = estrdup(editor);
206
 
    } else {
207
 
        editor = estrdup(def_editor);
208
 
        if ((cp = strchr(editor, ':')) != NULL)
209
 
            *cp = '\0';                 /* def_editor could be a path */
210
 
    }
 
195
    editor = find_editor();
211
196
 
212
197
    /*
213
198
     * Allocate space for the new argument vector and fill it in.
232
217
    nargv[ac] = NULL;
233
218
 
234
219
    /* Allow the editor to be suspended. */
235
 
    sigemptyset(&sa.sa_mask);
236
 
    sa.sa_flags = SA_RESTART;
237
 
    sa.sa_handler = SIG_DFL;
238
220
    (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
239
221
 
240
222
    /*
244
226
    gettime(&ts1);
245
227
    kidpid = fork();
246
228
    if (kidpid == -1) {
247
 
        warn("fork");
 
229
        warning("fork");
248
230
        goto cleanup;
249
231
    } else if (kidpid == 0) {
250
232
        /* child */
251
233
        (void) sigaction(SIGINT, &saved_sa_int, NULL);
252
234
        (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
253
235
        set_perms(PERM_FULL_USER);
254
 
        endpwent();
255
 
        endgrent();
256
 
        closefrom(STDERR_FILENO + 1);
 
236
        closefrom(def_closefrom + 1);
257
237
        execvp(nargv[0], nargv);
258
 
        warn("unable to execute %s", nargv[0]);
 
238
        warning("unable to execute %s", nargv[0]);
259
239
        _exit(127);
260
240
    }
261
241
 
299
279
        set_perms(PERM_ROOT);
300
280
        if (error || !S_ISREG(sb.st_mode)) {
301
281
            if (error)
302
 
                warn("%s", tf[i].tfile);
 
282
                warning("%s", tf[i].tfile);
303
283
            else
304
 
                warnx("%s: not a regular file", tf[i].tfile);
305
 
            warnx("%s left unmodified", tf[i].ofile);
 
284
                warningx("%s: not a regular file", tf[i].tfile);
 
285
            warningx("%s left unmodified", tf[i].ofile);
306
286
            if (tfd != -1)
307
287
                close(tfd);
308
288
            continue;
319
299
            timespecsub(&ts1, &ts2, &ts2);
320
300
#endif
321
301
            if (timespecisset(&ts2)) {
322
 
                warnx("%s unchanged", tf[i].ofile);
 
302
                warningx("%s unchanged", tf[i].ofile);
323
303
                unlink(tf[i].tfile);
324
304
                close(tfd);
325
305
                continue;
329
309
        ofd = open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT, 0644);
330
310
        set_perms(PERM_ROOT);
331
311
        if (ofd == -1) {
332
 
            warn("unable to write to %s", tf[i].ofile);
333
 
            warnx("contents of edit session left in %s", tf[i].tfile);
 
312
            warning("unable to write to %s", tf[i].ofile);
 
313
            warningx("contents of edit session left in %s", tf[i].tfile);
334
314
            close(tfd);
335
315
            continue;
336
316
        }
337
317
        while ((nread = read(tfd, buf, sizeof(buf))) > 0) {
338
318
            if ((nwritten = write(ofd, buf, nread)) != nread) {
339
319
                if (nwritten == -1)
340
 
                    warn("%s", tf[i].ofile);
 
320
                    warning("%s", tf[i].ofile);
341
321
                else
342
 
                    warnx("%s: short write", tf[i].ofile);
 
322
                    warningx("%s: short write", tf[i].ofile);
343
323
                break;
344
324
            }
345
325
        }
347
327
            /* success, got EOF */
348
328
            unlink(tf[i].tfile);
349
329
        } else if (nread < 0) {
350
 
            warn("unable to read temporary file");
351
 
            warnx("contents of edit session left in %s", tf[i].tfile);
 
330
            warning("unable to read temporary file");
 
331
            warningx("contents of edit session left in %s", tf[i].tfile);
352
332
        } else {
353
 
            warn("unable to write to %s", tf[i].ofile);
354
 
            warnx("contents of edit session left in %s", tf[i].tfile);
 
333
            warning("unable to write to %s", tf[i].ofile);
 
334
            warningx("contents of edit session left in %s", tf[i].tfile);
355
335
        }
356
336
        close(ofd);
357
337
    }
365
345
    }
366
346
    return(1);
367
347
}
 
348
 
 
349
/*
 
350
 * Determine which editor to use.  We don't bother restricting this
 
351
 * based on def_env_editor or def_editor since the editor runs with
 
352
 * the uid of the invoking user, not the runas (privileged) user.
 
353
 */
 
354
static char *
 
355
find_editor()
 
356
{
 
357
    char *cp, *editor = NULL, **ev, *ev0[4];
 
358
 
 
359
    ev0[0] = "SUDO_EDITOR";
 
360
    ev0[1] = "VISUAL";
 
361
    ev0[2] = "EDITOR";
 
362
    ev0[3] = NULL;
 
363
    for (ev = ev0; *ev != NULL; ev++) {
 
364
        if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
 
365
            if ((cp = strrchr(editor, '/')) != NULL)
 
366
                cp++;
 
367
            else
 
368
                cp = editor;
 
369
            /* Ignore "sudoedit" and "sudo" to avoid an endless loop. */
 
370
            if (strncmp(cp, "sudo", 4) != 0 ||
 
371
                (cp[4] != ' ' && cp[4] != '\0' && strcmp(cp + 4, "edit") != 0)) {
 
372
                editor = estrdup(editor);
 
373
                break;
 
374
            }
 
375
        }
 
376
        editor = NULL;
 
377
    }
 
378
    if (editor == NULL) {
 
379
        editor = estrdup(def_editor);
 
380
        if ((cp = strchr(editor, ':')) != NULL)
 
381
            *cp = '\0';                 /* def_editor could be a path */
 
382
    }
 
383
    return(editor);
 
384
}