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

« back to all changes in this revision

Viewing changes to plugins/sudoers/env.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) 2000-2005, 2007-2011
 
3
 *      Todd C. Miller <Todd.Miller@courtesan.com>
 
4
 *
 
5
 * Permission to use, copy, modify, and distribute this software for any
 
6
 * purpose with or without fee is hereby granted, provided that the above
 
7
 * copyright notice and this permission notice appear in all copies.
 
8
 *
 
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
16
 *
 
17
 * Sponsored in part by the Defense Advanced Research Projects
 
18
 * Agency (DARPA) and Air Force Research Laboratory, Air Force
 
19
 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
 
 
24
#include <sys/types.h>
 
25
#include <sys/param.h>
 
26
#include <sys/stat.h>
 
27
#include <stdio.h>
 
28
#ifdef STDC_HEADERS
 
29
# include <stdlib.h>
 
30
# include <stddef.h>
 
31
#else
 
32
# ifdef HAVE_STDLIB_H
 
33
#  include <stdlib.h>
 
34
# endif
 
35
#endif /* STDC_HEADERS */
 
36
#ifdef HAVE_STRING_H
 
37
# include <string.h>
 
38
#endif /* HAVE_STRING_H */
 
39
#ifdef HAVE_STRINGS_H
 
40
# include <strings.h>
 
41
#endif /* HAVE_STRINGS_H */
 
42
#ifdef HAVE_UNISTD_H
 
43
# include <unistd.h>
 
44
#endif /* HAVE_UNISTD_H */
 
45
#include <ctype.h>
 
46
#include <errno.h>
 
47
#include <pwd.h>
 
48
 
 
49
#include "sudoers.h"
 
50
 
 
51
/*
 
52
 * Flags used in rebuild_env()
 
53
 */
 
54
#undef DID_TERM
 
55
#define DID_TERM        0x0001
 
56
#undef DID_PATH
 
57
#define DID_PATH        0x0002
 
58
#undef DID_HOME
 
59
#define DID_HOME        0x0004
 
60
#undef DID_SHELL
 
61
#define DID_SHELL       0x0008
 
62
#undef DID_LOGNAME
 
63
#define DID_LOGNAME     0x0010
 
64
#undef DID_USER
 
65
#define DID_USER        0x0020
 
66
#undef DID_USERNAME
 
67
#define DID_USERNAME    0x0040
 
68
#undef DID_MAIL
 
69
#define DID_MAIL        0x0080
 
70
#undef DID_MAX
 
71
#define DID_MAX         0x00ff
 
72
 
 
73
#undef KEPT_TERM
 
74
#define KEPT_TERM       0x0100
 
75
#undef KEPT_PATH
 
76
#define KEPT_PATH       0x0200
 
77
#undef KEPT_HOME
 
78
#define KEPT_HOME       0x0400
 
79
#undef KEPT_SHELL
 
80
#define KEPT_SHELL      0x0800
 
81
#undef KEPT_LOGNAME
 
82
#define KEPT_LOGNAME    0x1000
 
83
#undef KEPT_USER
 
84
#define KEPT_USER       0x2000
 
85
#undef KEPT_USERNAME
 
86
#define KEPT_USERNAME   0x4000
 
87
#undef KEPT_MAIL
 
88
#define KEPT_MAIL       0x8000
 
89
#undef KEPT_MAX
 
90
#define KEPT_MAX        0xff00
 
91
 
 
92
struct environment {
 
93
    char **envp;                /* pointer to the new environment */
 
94
    size_t env_size;            /* size of new_environ in char **'s */
 
95
    size_t env_len;             /* number of slots used, not counting NULL */
 
96
};
 
97
 
 
98
/*
 
99
 * Prototypes
 
100
 */
 
101
static void sudo_setenv(const char *, const char *, int);
 
102
static void sudo_putenv(char *, int, int);
 
103
 
 
104
/*
 
105
 * Copy of the sudo-managed environment.
 
106
 */
 
107
static struct environment env;
 
108
 
 
109
/*
 
110
 * Default table of "bad" variables to remove from the environment.
 
111
 * XXX - how to omit TERMCAP if it starts with '/'?
 
112
 */
 
113
static const char *initial_badenv_table[] = {
 
114
    "IFS",
 
115
    "CDPATH",
 
116
    "LOCALDOMAIN",
 
117
    "RES_OPTIONS",
 
118
    "HOSTALIASES",
 
119
    "NLSPATH",
 
120
    "PATH_LOCALE",
 
121
    "LD_*",
 
122
    "_RLD*",
 
123
#ifdef __hpux
 
124
    "SHLIB_PATH",
 
125
#endif /* __hpux */
 
126
#ifdef _AIX
 
127
    "LDR_*",
 
128
    "LIBPATH",
 
129
    "AUTHSTATE",
 
130
#endif
 
131
#ifdef __APPLE__
 
132
    "DYLD_*",
 
133
#endif
 
134
#ifdef HAVE_KERB4
 
135
    "KRB_CONF*",
 
136
    "KRBCONFDIR",
 
137
    "KRBTKFILE",
 
138
#endif /* HAVE_KERB4 */
 
139
#ifdef HAVE_KERB5
 
140
    "KRB5_CONFIG*",
 
141
    "KRB5_KTNAME",
 
142
#endif /* HAVE_KERB5 */
 
143
#ifdef HAVE_SECURID
 
144
    "VAR_ACE",
 
145
    "USR_ACE",
 
146
    "DLC_ACE",
 
147
#endif /* HAVE_SECURID */
 
148
    "TERMINFO",                 /* terminfo, exclusive path to terminfo files */
 
149
    "TERMINFO_DIRS",            /* terminfo, path(s) to terminfo files */
 
150
    "TERMPATH",                 /* termcap, path(s) to termcap files */
 
151
    "TERMCAP",                  /* XXX - only if it starts with '/' */
 
152
    "ENV",                      /* ksh, file to source before script runs */
 
153
    "BASH_ENV",                 /* bash, file to source before script runs */
 
154
    "PS4",                      /* bash, prefix for lines in xtrace mode */
 
155
    "GLOBIGNORE",               /* bash, globbing patterns to ignore */
 
156
    "SHELLOPTS",                /* bash, extra command line options */
 
157
    "JAVA_TOOL_OPTIONS",        /* java, extra command line options */
 
158
    "PERLIO_DEBUG ",            /* perl, debugging output file */
 
159
    "PERLLIB",                  /* perl, search path for modules/includes */
 
160
    "PERL5LIB",                 /* perl 5, search path for modules/includes */
 
161
    "PERL5OPT",                 /* perl 5, extra command line options */
 
162
    "PERL5DB",                  /* perl 5, command used to load debugger */
 
163
    "FPATH",                    /* ksh, search path for functions */
 
164
    "NULLCMD",                  /* zsh, command for null file redirection */
 
165
    "READNULLCMD",              /* zsh, command for null file redirection */
 
166
    "ZDOTDIR",                  /* zsh, search path for dot files */
 
167
    "TMPPREFIX",                /* zsh, prefix for temporary files */
 
168
    "PYTHONHOME",               /* python, module search path */
 
169
    "PYTHONPATH",               /* python, search path */
 
170
    "PYTHONINSPECT",            /* python, allow inspection */
 
171
    "PYTHONUSERBASE",           /* python, per user site-packages directory */
 
172
    "RUBYLIB",                  /* ruby, library load path */
 
173
    "RUBYOPT",                  /* ruby, extra command line options */
 
174
    NULL
 
175
};
 
176
 
 
177
/*
 
178
 * Default table of variables to check for '%' and '/' characters.
 
179
 */
 
180
static const char *initial_checkenv_table[] = {
 
181
    "COLORTERM",
 
182
    "LANG",
 
183
    "LANGUAGE",
 
184
    "LC_*",
 
185
    "LINGUAS",
 
186
    "TERM",
 
187
    NULL
 
188
};
 
189
 
 
190
/*
 
191
 * Default table of variables to preserve in the environment.
 
192
 */
 
193
static const char *initial_keepenv_table[] = {
 
194
    "COLORS",
 
195
    "DISPLAY",
 
196
    "HOME",
 
197
    "HOSTNAME",
 
198
    "KRB5CCNAME",
 
199
    "LS_COLORS",
 
200
    "PATH",
 
201
    "PS1",
 
202
    "PS2",
 
203
    "TZ",
 
204
    "XAUTHORITY",
 
205
    "XAUTHORIZATION",
 
206
#ifdef _AIX
 
207
    "ODMDIR",
 
208
#endif
 
209
    NULL
 
210
};
 
211
 
 
212
/*
 
213
 * Initialize env based on envp.
 
214
 */
 
215
void
 
216
env_init(char * const envp[])
 
217
{
 
218
    char * const *ep;
 
219
    size_t len;
 
220
 
 
221
    for (ep = envp; *ep != NULL; ep++)
 
222
        continue;
 
223
    len = (size_t)(ep - envp);
 
224
 
 
225
    env.env_len = len;
 
226
    env.env_size = len + 1 + 128;
 
227
    env.envp = emalloc2(env.env_size, sizeof(char *));
 
228
#ifdef ENV_DEBUG
 
229
    memset(env.envp, 0, env.env_size * sizeof(char *));
 
230
#endif
 
231
    memcpy(env.envp, envp, len * sizeof(char *));
 
232
    env.envp[len] = '\0';
 
233
}
 
234
 
 
235
char **
 
236
env_get(void)
 
237
{
 
238
    return env.envp;
 
239
}
 
240
 
 
241
/*
 
242
 * Similar to setenv(3) but operates on sudo's private copy of the environment
 
243
 * (not environ) and it always overwrites.  The dupcheck param determines
 
244
 * whether we need to verify that the variable is not already set.
 
245
 */
 
246
static void
 
247
sudo_setenv(const char *var, const char *val, int dupcheck)
 
248
{
 
249
    char *estring;
 
250
    size_t esize;
 
251
 
 
252
    esize = strlen(var) + 1 + strlen(val) + 1;
 
253
    estring = emalloc(esize);
 
254
 
 
255
    /* Build environment string and insert it. */
 
256
    if (strlcpy(estring, var, esize) >= esize ||
 
257
        strlcat(estring, "=", esize) >= esize ||
 
258
        strlcat(estring, val, esize) >= esize) {
 
259
 
 
260
        errorx(1, _("internal error, sudo_setenv() overflow"));
 
261
    }
 
262
    sudo_putenv(estring, dupcheck, TRUE);
 
263
}
 
264
 
 
265
/*
 
266
 * Similar to putenv(3) but operates on sudo's private copy of the
 
267
 * environment (not environ) and it always overwrites.  The dupcheck param
 
268
 * determines whether we need to verify that the variable is not already set.
 
269
 * Will only overwrite an existing variable if overwrite is set.
 
270
 */
 
271
static void
 
272
sudo_putenv(char *str, int dupcheck, int overwrite)
 
273
{
 
274
    char **ep;
 
275
    size_t len;
 
276
    int found = FALSE;
 
277
 
 
278
    /* Make sure there is room for the new entry plus a NULL. */
 
279
    if (env.env_len + 2 > env.env_size) {
 
280
        env.env_size += 128;
 
281
        env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
 
282
#ifdef ENV_DEBUG
 
283
        memset(env.envp + env.env_len, 0,
 
284
            (env.env_size - env.env_len) * sizeof(char *));
 
285
#endif
 
286
    }
 
287
 
 
288
#ifdef ENV_DEBUG
 
289
    if (env.envp[env.env_len] != NULL)
 
290
        errorx(1, _("sudo_putenv: corrupted envp, length mismatch"));
 
291
#endif
 
292
 
 
293
    if (dupcheck) {
 
294
        len = (strchr(str, '=') - str) + 1;
 
295
        for (ep = env.envp; !found && *ep != NULL; ep++) {
 
296
            if (strncmp(str, *ep, len) == 0) {
 
297
                if (overwrite)
 
298
                    *ep = str;
 
299
                found = TRUE;
 
300
            }
 
301
        }
 
302
        /* Prune out duplicate variables. */
 
303
        if (found && overwrite) {
 
304
            while (*ep != NULL) {
 
305
                if (strncmp(str, *ep, len) == 0) {
 
306
                    char **cur = ep;
 
307
                    while ((*cur = *(cur + 1)) != NULL)
 
308
                        cur++;
 
309
                } else {
 
310
                    ep++;
 
311
                }
 
312
            }
 
313
            env.env_len = ep - env.envp;
 
314
        }
 
315
    }
 
316
 
 
317
    if (!found) {
 
318
        ep = env.envp + env.env_len;
 
319
        env.env_len++;
 
320
        *ep++ = str;
 
321
        *ep = NULL;
 
322
    }
 
323
}
 
324
 
 
325
/*
 
326
 * Check the env_delete blacklist.
 
327
 * Returns TRUE if the variable was found, else false.
 
328
 */
 
329
static int
 
330
matches_env_delete(const char *var)
 
331
{
 
332
    struct list_member *cur;
 
333
    size_t len;
 
334
    int iswild, match = FALSE;
 
335
 
 
336
    /* Skip anything listed in env_delete. */
 
337
    for (cur = def_env_delete; cur; cur = cur->next) {
 
338
        len = strlen(cur->value);
 
339
        /* Deal with '*' wildcard */
 
340
        if (cur->value[len - 1] == '*') {
 
341
            len--;
 
342
            iswild = TRUE;
 
343
        } else
 
344
            iswild = FALSE;
 
345
        if (strncmp(cur->value, var, len) == 0 &&
 
346
            (iswild || var[len] == '=')) {
 
347
            match = TRUE;
 
348
            break;
 
349
        }
 
350
    }
 
351
    return match;
 
352
}
 
353
 
 
354
/*
 
355
 * Apply the env_check list.
 
356
 * Returns TRUE if the variable is allowed, FALSE if denied
 
357
 * or -1 if no match.
 
358
 */
 
359
static int
 
360
matches_env_check(const char *var)
 
361
{
 
362
    struct list_member *cur;
 
363
    size_t len;
 
364
    int iswild, keepit = -1;
 
365
 
 
366
    for (cur = def_env_check; cur; cur = cur->next) {
 
367
        len = strlen(cur->value);
 
368
        /* Deal with '*' wildcard */
 
369
        if (cur->value[len - 1] == '*') {
 
370
            len--;
 
371
            iswild = TRUE;
 
372
        } else
 
373
            iswild = FALSE;
 
374
        if (strncmp(cur->value, var, len) == 0 &&
 
375
            (iswild || var[len] == '=')) {
 
376
            keepit = !strpbrk(var, "/%");
 
377
            break;
 
378
        }
 
379
    }
 
380
    return keepit;
 
381
}
 
382
 
 
383
/*
 
384
 * Check the env_keep list.
 
385
 * Returns TRUE if the variable is allowed else FALSE.
 
386
 */
 
387
static int
 
388
matches_env_keep(const char *var)
 
389
{
 
390
    struct list_member *cur;
 
391
    size_t len;
 
392
    int iswild, keepit = FALSE;
 
393
 
 
394
    /* Preserve SHELL variable for "sudo -s". */
 
395
    if (ISSET(sudo_mode, MODE_SHELL) && strncmp(var, "SHELL=", 6) == 0)
 
396
        return TRUE;
 
397
 
 
398
    for (cur = def_env_keep; cur; cur = cur->next) {
 
399
        len = strlen(cur->value);
 
400
        /* Deal with '*' wildcard */
 
401
        if (cur->value[len - 1] == '*') {
 
402
            len--;
 
403
            iswild = TRUE;
 
404
        } else
 
405
            iswild = FALSE;
 
406
        if (strncmp(cur->value, var, len) == 0 &&
 
407
            (iswild || var[len] == '=')) {
 
408
            keepit = TRUE;
 
409
            break;
 
410
        }
 
411
    }
 
412
    return keepit;
 
413
}
 
414
 
 
415
/*
 
416
 * Build a new environment and ether clear potentially dangerous
 
417
 * variables from the old one or start with a clean slate.
 
418
 * Also adds sudo-specific variables (SUDO_*).
 
419
 */
 
420
void
 
421
rebuild_env(void)
 
422
{
 
423
    char **old_envp, **ep, *cp, *ps1;
 
424
    char idbuf[MAX_UID_T_LEN];
 
425
    unsigned int didvar;
 
426
    int reset_home = FALSE;
 
427
 
 
428
    /*
 
429
     * Either clean out the environment or reset to a safe default.
 
430
     */
 
431
    ps1 = NULL;
 
432
    didvar = 0;
 
433
    env.env_len = 0;
 
434
    env.env_size = 128;
 
435
    old_envp = env.envp;
 
436
    env.envp = emalloc2(env.env_size, sizeof(char *));
 
437
#ifdef ENV_DEBUG
 
438
    memset(env.envp, 0, env.env_size * sizeof(char *));
 
439
#endif
 
440
 
 
441
    /* Reset HOME based on target user if configured to. */
 
442
    if (ISSET(sudo_mode, MODE_RUN)) {
 
443
        if (def_always_set_home ||
 
444
            ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) || 
 
445
            (ISSET(sudo_mode, MODE_SHELL) && def_set_home))
 
446
            reset_home = TRUE;
 
447
    }
 
448
 
 
449
    if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
 
450
        /* Pull in vars we want to keep from the old environment. */
 
451
        for (ep = old_envp; *ep; ep++) {
 
452
            int keepit;
 
453
 
 
454
            /* Skip variables with values beginning with () (bash functions) */
 
455
            if ((cp = strchr(*ep, '=')) != NULL) {
 
456
                if (strncmp(cp, "=() ", 3) == 0)
 
457
                    continue;
 
458
            }
 
459
 
 
460
            /*
 
461
             * First check certain variables for '%' and '/' characters.
 
462
             * If no match there, check the keep list.
 
463
             * If nothing matched, we remove it from the environment.
 
464
             */
 
465
            keepit = matches_env_check(*ep);
 
466
            if (keepit == -1)
 
467
                keepit = matches_env_keep(*ep);
 
468
 
 
469
            /* For SUDO_PS1 -> PS1 conversion. */
 
470
            if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
 
471
                ps1 = *ep + 5;
 
472
 
 
473
            if (keepit) {
 
474
                /* Preserve variable. */
 
475
                switch (**ep) {
 
476
                    case 'H':
 
477
                        if (strncmp(*ep, "HOME=", 5) == 0)
 
478
                            SET(didvar, DID_HOME);
 
479
                        break;
 
480
                    case 'L':
 
481
                        if (strncmp(*ep, "LOGNAME=", 8) == 0)
 
482
                            SET(didvar, DID_LOGNAME);
 
483
                        break;
 
484
                    case 'M':
 
485
                        if (strncmp(*ep, "MAIL=", 5) == 0)
 
486
                            SET(didvar, DID_MAIL);
 
487
                        break;
 
488
                    case 'P':
 
489
                        if (strncmp(*ep, "PATH=", 5) == 0)
 
490
                            SET(didvar, DID_PATH);
 
491
                        break;
 
492
                    case 'S':
 
493
                        if (strncmp(*ep, "SHELL=", 6) == 0)
 
494
                            SET(didvar, DID_SHELL);
 
495
                        break;
 
496
                    case 'T':
 
497
                        if (strncmp(*ep, "TERM=", 5) == 0)
 
498
                            SET(didvar, DID_TERM);
 
499
                        break;
 
500
                    case 'U':
 
501
                        if (strncmp(*ep, "USER=", 5) == 0)
 
502
                            SET(didvar, DID_USER);
 
503
                        if (strncmp(*ep, "USERNAME=", 5) == 0)
 
504
                            SET(didvar, DID_USERNAME);
 
505
                        break;
 
506
                }
 
507
                sudo_putenv(*ep, FALSE, FALSE);
 
508
            }
 
509
        }
 
510
        didvar |= didvar << 8;          /* convert DID_* to KEPT_* */
 
511
 
 
512
        /*
 
513
         * Add in defaults.  In -i mode these come from the runas user,
 
514
         * otherwise they may be from the user's environment (depends
 
515
         * on sudoers options).
 
516
         */
 
517
        if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
 
518
            sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
 
519
            sudo_setenv("LOGNAME", runas_pw->pw_name,
 
520
                ISSET(didvar, DID_LOGNAME));
 
521
            sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER));
 
522
            sudo_setenv("USERNAME", runas_pw->pw_name,
 
523
                ISSET(didvar, DID_USERNAME));
 
524
        } else {
 
525
            if (!ISSET(didvar, DID_SHELL))
 
526
                sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
 
527
            if (!ISSET(didvar, DID_LOGNAME))
 
528
                sudo_setenv("LOGNAME", user_name, FALSE);
 
529
            if (!ISSET(didvar, DID_USER))
 
530
                sudo_setenv("USER", user_name, FALSE);
 
531
            if (!ISSET(didvar, DID_USERNAME))
 
532
                sudo_setenv("USERNAME", user_name, FALSE);
 
533
        }
 
534
 
 
535
        /* If we didn't keep HOME, reset it based on target user. */
 
536
        if (!ISSET(didvar, KEPT_HOME))
 
537
            reset_home = TRUE;
 
538
 
 
539
        /*
 
540
         * Set MAIL to target user in -i mode or if MAIL is not preserved
 
541
         * from user's environment.
 
542
         */
 
543
        if (ISSET(sudo_mode, MODE_LOGIN_SHELL) || !ISSET(didvar, KEPT_MAIL)) {
 
544
            cp = _PATH_MAILDIR;
 
545
            if (cp[sizeof(_PATH_MAILDIR) - 2] == '/')
 
546
                easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name);
 
547
            else
 
548
                easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name);
 
549
            sudo_putenv(cp, ISSET(didvar, DID_MAIL), TRUE);
 
550
        }
 
551
    } else {
 
552
        /*
 
553
         * Copy environ entries as long as they don't match env_delete or
 
554
         * env_check.
 
555
         */
 
556
        for (ep = old_envp; *ep; ep++) {
 
557
            int okvar;
 
558
 
 
559
            /* Skip variables with values beginning with () (bash functions) */
 
560
            if ((cp = strchr(*ep, '=')) != NULL) {
 
561
                if (strncmp(cp, "=() ", 3) == 0)
 
562
                    continue;
 
563
            }
 
564
 
 
565
            /*
 
566
             * First check variables against the blacklist in env_delete.
 
567
             * If no match there check for '%' and '/' characters.
 
568
             */
 
569
            okvar = matches_env_delete(*ep) != TRUE;
 
570
            if (okvar)
 
571
                okvar = matches_env_check(*ep) != FALSE;
 
572
 
 
573
            if (okvar) {
 
574
                if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
 
575
                    ps1 = *ep + 5;
 
576
                else if (strncmp(*ep, "PATH=", 5) == 0)
 
577
                    SET(didvar, DID_PATH);
 
578
                else if (strncmp(*ep, "TERM=", 5) == 0)
 
579
                    SET(didvar, DID_TERM);
 
580
                sudo_putenv(*ep, FALSE, FALSE);
 
581
            }
 
582
        }
 
583
    }
 
584
    /* Replace the PATH envariable with a secure one? */
 
585
    if (def_secure_path && !user_is_exempt()) {
 
586
        sudo_setenv("PATH", def_secure_path, TRUE);
 
587
        SET(didvar, DID_PATH);
 
588
    }
 
589
 
 
590
    /*
 
591
     * Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is not
 
592
     * disabled.  We skip this if we are running a login shell (because
 
593
     * they have already been set them) or sudoedit (because we want the
 
594
     * editor to find the user's startup files).
 
595
     */
 
596
    if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL|MODE_EDIT)) {
 
597
        if (!ISSET(didvar, KEPT_LOGNAME))
 
598
            sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
 
599
        if (!ISSET(didvar, KEPT_USER))
 
600
            sudo_setenv("USER", runas_pw->pw_name, TRUE);
 
601
        if (!ISSET(didvar, KEPT_USERNAME))
 
602
            sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
 
603
    }
 
604
 
 
605
    /* Set $HOME to target user if not preserving user's value. */
 
606
    if (reset_home)
 
607
        sudo_setenv("HOME", runas_pw->pw_dir, TRUE);
 
608
 
 
609
    /* Provide default values for $TERM and $PATH if they are not set. */
 
610
    if (!ISSET(didvar, DID_TERM))
 
611
        sudo_putenv("TERM=unknown", FALSE, FALSE);
 
612
    if (!ISSET(didvar, DID_PATH))
 
613
        sudo_setenv("PATH", _PATH_STDPATH, FALSE);
 
614
 
 
615
    /* Set PS1 if SUDO_PS1 is set. */
 
616
    if (ps1 != NULL)
 
617
        sudo_putenv(ps1, TRUE, TRUE);
 
618
 
 
619
    /* Add the SUDO_COMMAND envariable (cmnd + args). */
 
620
    if (user_args) {
 
621
        easprintf(&cp, "%s %s", user_cmnd, user_args);
 
622
        sudo_setenv("SUDO_COMMAND", cp, TRUE);
 
623
        efree(cp);
 
624
    } else {
 
625
        sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE);
 
626
    }
 
627
 
 
628
    /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
 
629
    sudo_setenv("SUDO_USER", user_name, TRUE);
 
630
    snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid);
 
631
    sudo_setenv("SUDO_UID", idbuf, TRUE);
 
632
    snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid);
 
633
    sudo_setenv("SUDO_GID", idbuf, TRUE);
 
634
 
 
635
    /* Free old environment. */
 
636
    efree(old_envp);
 
637
}
 
638
 
 
639
void
 
640
insert_env_vars(char * const envp[])
 
641
{
 
642
    char * const *ep;
 
643
 
 
644
    if (envp == NULL)
 
645
        return;
 
646
 
 
647
    /* Add user-specified environment variables. */
 
648
    for (ep = envp; *ep != NULL; ep++)
 
649
        sudo_putenv(*ep, TRUE, TRUE);
 
650
}
 
651
 
 
652
/*
 
653
 * Validate the list of environment variables passed in on the command
 
654
 * line against env_delete, env_check, and env_keep.
 
655
 * Calls log_error() if any specified variables are not allowed.
 
656
 */
 
657
void
 
658
validate_env_vars(char * const env_vars[])
 
659
{
 
660
    char * const *ep;
 
661
    char *eq, *bad = NULL;
 
662
    size_t len, blen = 0, bsize = 0;
 
663
    int okvar;
 
664
 
 
665
    if (env_vars == NULL)
 
666
        return;
 
667
 
 
668
    /* Add user-specified environment variables. */
 
669
    for (ep = env_vars; *ep != NULL; ep++) {
 
670
        if (def_secure_path && !user_is_exempt() &&
 
671
            strncmp(*ep, "PATH=", 5) == 0) {
 
672
            okvar = FALSE;
 
673
        } else if (def_env_reset) {
 
674
            okvar = matches_env_check(*ep);
 
675
            if (okvar == -1)
 
676
                okvar = matches_env_keep(*ep);
 
677
        } else {
 
678
            okvar = matches_env_delete(*ep) == FALSE;
 
679
            if (okvar == FALSE)
 
680
                okvar = matches_env_check(*ep) != FALSE;
 
681
        }
 
682
        if (okvar == FALSE) {
 
683
            /* Not allowed, add to error string, allocating as needed. */
 
684
            if ((eq = strchr(*ep, '=')) != NULL)
 
685
                *eq = '\0';
 
686
            len = strlen(*ep) + 2;
 
687
            if (blen + len >= bsize) {
 
688
                do {
 
689
                    bsize += 1024;
 
690
                } while (blen + len >= bsize);
 
691
                bad = erealloc(bad, bsize);
 
692
                bad[blen] = '\0';
 
693
            }
 
694
            strlcat(bad, *ep, bsize);
 
695
            strlcat(bad, ", ", bsize);
 
696
            blen += len;
 
697
            if (eq != NULL)
 
698
                *eq = '=';
 
699
        }
 
700
    }
 
701
    if (bad != NULL) {
 
702
        bad[blen - 2] = '\0';           /* remove trailing ", " */
 
703
        log_error(NO_MAIL,
 
704
            _("sorry, you are not allowed to set the following environment variables: %s"), bad);
 
705
        /* NOTREACHED */
 
706
        efree(bad);
 
707
    }
 
708
}
 
709
 
 
710
/*
 
711
 * Read in /etc/environment ala AIX and Linux.
 
712
 * Lines may be in either of three formats:
 
713
 *  NAME=VALUE
 
714
 *  NAME="VALUE"
 
715
 *  NAME='VALUE'
 
716
 * with an optional "export" prefix so the shell can source the file.
 
717
 * Invalid lines, blank lines, or lines consisting solely of a comment
 
718
 * character are skipped.
 
719
 */
 
720
void
 
721
read_env_file(const char *path, int overwrite)
 
722
{
 
723
    FILE *fp;
 
724
    char *cp, *var, *val;
 
725
    size_t var_len, val_len;
 
726
 
 
727
    if ((fp = fopen(path, "r")) == NULL)
 
728
        return;
 
729
 
 
730
    while ((var = sudo_parseln(fp)) != NULL) {
 
731
        /* Skip blank or comment lines */
 
732
        if (*var == '\0')
 
733
            continue;
 
734
 
 
735
        /* Skip optional "export " */
 
736
        if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) {
 
737
            var += 7;
 
738
            while (isspace((unsigned char) *var)) {
 
739
                var++;
 
740
            }
 
741
        }
 
742
 
 
743
        /* Must be of the form name=["']value['"] */
 
744
        for (val = var; *val != '\0' && *val != '='; val++)
 
745
            ;
 
746
        if (var == val || *val != '=')
 
747
            continue;
 
748
        var_len = (size_t)(val - var);
 
749
        val_len = strlen(++val);
 
750
 
 
751
        /* Strip leading and trailing single/double quotes */
 
752
        if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
 
753
            val[val_len - 1] = '\0';
 
754
            val++;
 
755
            val_len -= 2;
 
756
        }
 
757
 
 
758
        cp = emalloc(var_len + 1 + val_len + 1);
 
759
        memcpy(cp, var, var_len + 1); /* includes '=' */
 
760
        memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
 
761
 
 
762
        sudo_putenv(cp, TRUE, overwrite);
 
763
    }
 
764
    fclose(fp);
 
765
}
 
766
 
 
767
void
 
768
init_envtables(void)
 
769
{
 
770
    struct list_member *cur;
 
771
    const char **p;
 
772
 
 
773
    /* Fill in the "env_delete" list. */
 
774
    for (p = initial_badenv_table; *p; p++) {
 
775
        cur = emalloc(sizeof(struct list_member));
 
776
        cur->value = estrdup(*p);
 
777
        cur->next = def_env_delete;
 
778
        def_env_delete = cur;
 
779
    }
 
780
 
 
781
    /* Fill in the "env_check" list. */
 
782
    for (p = initial_checkenv_table; *p; p++) {
 
783
        cur = emalloc(sizeof(struct list_member));
 
784
        cur->value = estrdup(*p);
 
785
        cur->next = def_env_check;
 
786
        def_env_check = cur;
 
787
    }
 
788
 
 
789
    /* Fill in the "env_keep" list. */
 
790
    for (p = initial_keepenv_table; *p; p++) {
 
791
        cur = emalloc(sizeof(struct list_member));
 
792
        cur->value = estrdup(*p);
 
793
        cur->next = def_env_keep;
 
794
        def_env_keep = cur;
 
795
    }
 
796
}