~ubuntu-branches/ubuntu/oneiric/sudo/oneiric-security

« back to all changes in this revision

Viewing changes to .pc/debian-changes-1.7.4p4-5/env.c

  • Committer: Package Import Robot
  • Author(s): Tyler Hicks
  • Date: 2012-05-15 23:28:04 UTC
  • Revision ID: package-import@ubuntu.com-20120515232804-2rd0d4k222la647h
Tags: 1.7.4p6-1ubuntu2.1
* SECURITY UPDATE: Properly handle multiple netmasks in sudoers Host and
  Host_List values
  - debian/patches/CVE-2012-2337.patch: Don't perform IPv6 checks on IPv4
    addresses. Based on upstream patch.
  - CVE-2012-2337

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 2000-2005, 2007-2010
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 "sudo.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
 
    int owned;                  /* do we own envp or is it the system's? */
97
 
};
98
 
 
99
 
/*
100
 
 * Prototypes
101
 
 */
102
 
static void sudo_setenv         __P((const char *, const char *, int));
103
 
static void sudo_putenv         __P((char *, int, int));
104
 
 
105
 
extern char **environ;          /* global environment */
106
 
 
107
 
/*
108
 
 * Copy of the sudo-managed environment.
109
 
 */
110
 
static struct environment env;
111
 
 
112
 
/*
113
 
 * Default table of "bad" variables to remove from the environment.
114
 
 * XXX - how to omit TERMCAP if it starts with '/'?
115
 
 */
116
 
static const char *initial_badenv_table[] = {
117
 
    "IFS",
118
 
    "CDPATH",
119
 
    "SHELLOPTS",
120
 
    "PS4",
121
 
    "LOCALDOMAIN",
122
 
    "RES_OPTIONS",
123
 
    "HOSTALIASES",
124
 
    "NLSPATH",
125
 
    "PATH_LOCALE",
126
 
    "LD_*",
127
 
    "_RLD*",
128
 
#ifdef __hpux
129
 
    "SHLIB_PATH",
130
 
#endif /* __hpux */
131
 
#ifdef _AIX
132
 
    "LDR_*",
133
 
    "LIBPATH",
134
 
    "AUTHSTATE",
135
 
#endif
136
 
#ifdef __APPLE__
137
 
    "DYLD_*",
138
 
#endif
139
 
#ifdef HAVE_KERB4
140
 
    "KRB_CONF*",
141
 
    "KRBCONFDIR",
142
 
    "KRBTKFILE",
143
 
#endif /* HAVE_KERB4 */
144
 
#ifdef HAVE_KERB5
145
 
    "KRB5_CONFIG*",
146
 
    "KRB5_KTNAME",
147
 
#endif /* HAVE_KERB5 */
148
 
#ifdef HAVE_SECURID
149
 
    "VAR_ACE",
150
 
    "USR_ACE",
151
 
    "DLC_ACE",
152
 
#endif /* HAVE_SECURID */
153
 
    "TERMINFO",                 /* terminfo, exclusive path to terminfo files */
154
 
    "TERMINFO_DIRS",            /* terminfo, path(s) to terminfo files */
155
 
    "TERMPATH",                 /* termcap, path(s) to termcap files */
156
 
    "TERMCAP",                  /* XXX - only if it starts with '/' */
157
 
    "ENV",                      /* ksh, file to source before script runs */
158
 
    "BASH_ENV",                 /* bash, file to source before script runs */
159
 
    "PS4",                      /* bash, prefix for lines in xtrace mode */
160
 
    "GLOBIGNORE",               /* bash, globbing patterns to ignore */
161
 
    "SHELLOPTS",                /* bash, extra command line options */
162
 
    "JAVA_TOOL_OPTIONS",        /* java, extra command line options */
163
 
    "PERLIO_DEBUG ",            /* perl, debugging output file */
164
 
    "PERLLIB",                  /* perl, search path for modules/includes */
165
 
    "PERL5LIB",                 /* perl 5, search path for modules/includes */
166
 
    "PERL5OPT",                 /* perl 5, extra command line options */
167
 
    "PERL5DB",                  /* perl 5, command used to load debugger */
168
 
    "FPATH",                    /* ksh, search path for functions */
169
 
    "NULLCMD",                  /* zsh, command for null file redirection */
170
 
    "READNULLCMD",              /* zsh, command for null file redirection */
171
 
    "ZDOTDIR",                  /* zsh, search path for dot files */
172
 
    "TMPPREFIX",                /* zsh, prefix for temporary files */
173
 
    "PYTHONHOME",               /* python, module search path */
174
 
    "PYTHONPATH",               /* python, search path */
175
 
    "PYTHONINSPECT",            /* python, allow inspection */
176
 
    "PYTHONUSERBASE",           /* python, per user site-packages directory */
177
 
    "RUBYLIB",                  /* ruby, library load path */
178
 
    "RUBYOPT",                  /* ruby, extra command line options */
179
 
    NULL
180
 
};
181
 
 
182
 
/*
183
 
 * Default table of variables to check for '%' and '/' characters.
184
 
 */
185
 
static const char *initial_checkenv_table[] = {
186
 
    "COLORTERM",
187
 
    "LANG",
188
 
    "LANGUAGE",
189
 
    "LC_*",
190
 
    "LINGUAS",
191
 
    "TERM",
192
 
    NULL
193
 
};
194
 
 
195
 
/*
196
 
 * Default table of variables to preserve in the environment.
197
 
 */
198
 
static const char *initial_keepenv_table[] = {
199
 
    "COLORS",
200
 
    "DISPLAY",
201
 
    "HOSTNAME",
202
 
    "KRB5CCNAME",
203
 
    "LS_COLORS",
204
 
    "PATH",
205
 
    "PS1",
206
 
    "PS2",
207
 
    "TZ",
208
 
    "XAUTHORITY",
209
 
    "XAUTHORIZATION",
210
 
    NULL
211
 
};
212
 
 
213
 
/*
214
 
 * Initialize env based on envp.
215
 
 */
216
 
void
217
 
env_init(lazy)
218
 
    int lazy;
219
 
{
220
 
    char * const *ep;
221
 
    size_t len;
222
 
 
223
 
    for (ep = environ; *ep != NULL; ep++)
224
 
        continue;
225
 
    len = (size_t)(ep - environ);
226
 
 
227
 
    if (lazy) {
228
 
        /*
229
 
         * If we are already initialized due to lazy init (usualy via getenv())
230
 
         * we need to avoid calling malloc() as it may call getenv() itself.
231
 
         */
232
 
        env.envp = environ;
233
 
        env.env_len = len;
234
 
        env.env_size = len;
235
 
    } else if (!env.owned) {
236
 
        env.env_len = len;
237
 
        env.env_size = len + 1 + 128;
238
 
        env.envp = emalloc2(env.env_size, sizeof(char *));
239
 
#ifdef ENV_DEBUG
240
 
        memset(env.envp, 0, env.env_size * sizeof(char *));
241
 
#endif
242
 
        memcpy(env.envp, environ, len * sizeof(char *));
243
 
        env.envp[len] = '\0';
244
 
        env.owned = TRUE;
245
 
    }
246
 
}
247
 
 
248
 
char **
249
 
env_get()
250
 
{
251
 
    return env.envp;
252
 
}
253
 
 
254
 
/*
255
 
 * Similar to setenv(3) but operates on sudo's private copy of the environment
256
 
 * (not environ) and it always overwrites.  The dupcheck param determines
257
 
 * whether we need to verify that the variable is not already set.
258
 
 */
259
 
static void
260
 
sudo_setenv(var, val, dupcheck)
261
 
    const char *var;
262
 
    const char *val;
263
 
    int dupcheck;
264
 
{
265
 
    char *estring;
266
 
    size_t esize;
267
 
 
268
 
    esize = strlen(var) + 1 + strlen(val) + 1;
269
 
    estring = emalloc(esize);
270
 
 
271
 
    /* Build environment string and insert it. */
272
 
    if (strlcpy(estring, var, esize) >= esize ||
273
 
        strlcat(estring, "=", esize) >= esize ||
274
 
        strlcat(estring, val, esize) >= esize) {
275
 
 
276
 
        errorx(1, "internal error, sudo_setenv() overflow");
277
 
    }
278
 
    sudo_putenv(estring, dupcheck, TRUE);
279
 
}
280
 
 
281
 
/*
282
 
 * Version of getenv(3) that uses our own environ pointer.
283
 
 */
284
 
char *
285
 
getenv(var)
286
 
    const char *var;
287
 
{
288
 
    char *cp, **ev;
289
 
    size_t vlen = strlen(var);
290
 
 
291
 
    if (env.envp == NULL)
292
 
        env_init(TRUE);
293
 
 
294
 
    for (ev = env.envp; (cp = *ev) != NULL; ev++) {
295
 
        if (strncmp(var, cp, vlen) == 0 && cp[vlen] == '=')
296
 
            return cp + vlen + 1;
297
 
    }
298
 
    return NULL;
299
 
}
300
 
 
301
 
/*
302
 
 * Version of setenv(3) that uses our own environ pointer.
303
 
 */
304
 
int
305
 
setenv(var, val, overwrite)
306
 
    const char *var;
307
 
    const char *val;
308
 
    int overwrite;
309
 
{
310
 
    char *estring, *ep;
311
 
    const char *cp;
312
 
    size_t esize;
313
 
 
314
 
    if (!var || *var == '\0') {
315
 
        errno = EINVAL;
316
 
        return(-1);
317
 
    }
318
 
 
319
 
    if (env.envp == NULL)
320
 
        env_init(TRUE);
321
 
 
322
 
    /*
323
 
     * POSIX says a var name with '=' is an error but BSD
324
 
     * just ignores the '=' and anything after it.
325
 
     */
326
 
    for (cp = var; *cp && *cp != '='; cp++)
327
 
        ;
328
 
    esize = (size_t)(cp - var) + 2;
329
 
    if (val) {
330
 
        esize += strlen(val);   /* glibc treats a NULL val as "" */
331
 
    }
332
 
 
333
 
    /* Allocate and fill in estring. */
334
 
    estring = ep = emalloc(esize);
335
 
    for (cp = var; *cp && *cp != '='; cp++)
336
 
        *ep++ = *cp;
337
 
    *ep++ = '=';
338
 
    if (val) {
339
 
        for (cp = val; *cp; cp++)
340
 
            *ep++ = *cp;
341
 
    }
342
 
    *ep = '\0';
343
 
 
344
 
#ifdef ENV_DEBUG
345
 
    if (env.envp[env.env_len] != NULL)
346
 
        errorx(1, "setenv: corrupted envp, len mismatch");
347
 
#endif
348
 
    sudo_putenv(estring, TRUE, overwrite);
349
 
    return(0);
350
 
}
351
 
 
352
 
/*
353
 
 * Version of unsetenv(3) that uses our own environ pointer.
354
 
 */
355
 
#ifdef UNSETENV_VOID
356
 
void
357
 
#else
358
 
int
359
 
#endif
360
 
unsetenv(var)
361
 
    const char *var;
362
 
{
363
 
    char **ep;
364
 
    size_t len;
365
 
 
366
 
    if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) {
367
 
        errno = EINVAL;
368
 
#ifdef UNSETENV_VOID
369
 
        return;
370
 
#else
371
 
        return(-1);
372
 
#endif
373
 
    }
374
 
 
375
 
    if (env.envp == NULL)
376
 
        env_init(TRUE);
377
 
 
378
 
#ifdef ENV_DEBUG
379
 
    if (env.envp[env.env_len] != NULL)
380
 
        errorx(1, "unsetenv: corrupted envp, len mismatch");
381
 
#endif
382
 
 
383
 
    len = strlen(var);
384
 
    for (ep = env.envp; *ep != NULL;) {
385
 
        if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
386
 
            /* Found it; shift remainder + NULL over by one. */
387
 
            char **cur = ep;
388
 
            while ((*cur = *(cur + 1)) != NULL)
389
 
                cur++;
390
 
            /* Keep going, could be multiple instances of the var. */
391
 
        } else {
392
 
            ep++;
393
 
        }
394
 
    }
395
 
    env.env_len = ep - env.envp;
396
 
#ifndef UNSETENV_VOID
397
 
    return(0);
398
 
#endif
399
 
}
400
 
 
401
 
/*
402
 
 * Version of putenv(3) that uses our own environ pointer.
403
 
 */
404
 
int
405
 
#ifdef PUTENV_CONST
406
 
putenv(const char *string)
407
 
#else
408
 
putenv(string)
409
 
    char *string;
410
 
#endif
411
 
{
412
 
    if (env.envp == NULL)
413
 
        env_init(TRUE);
414
 
 
415
 
    if (strchr(string, '=') == NULL) {
416
 
        errno = EINVAL;
417
 
        return(-1);
418
 
    }
419
 
#ifdef ENV_DEBUG
420
 
    if (env.envp[env.env_len] != NULL)
421
 
        errorx(1, "putenv: corrupted envp, len mismatch");
422
 
#endif
423
 
    sudo_putenv((char *)string, TRUE, TRUE);
424
 
    return(0);
425
 
}
426
 
 
427
 
/*
428
 
 * Similar to putenv(3) but operates on sudo's private copy of the
429
 
 * environment (not environ) and it always overwrites.  The dupcheck param
430
 
 * determines whether we need to verify that the variable is not already set.
431
 
 * Will only overwrite an existing variable if overwrite is set.
432
 
 */
433
 
static void
434
 
sudo_putenv(str, dupcheck, overwrite)
435
 
    char *str;
436
 
    int dupcheck;
437
 
    int overwrite;
438
 
{
439
 
    char **ep;
440
 
    size_t len;
441
 
    int found = FALSE;
442
 
 
443
 
    /* Make sure there is room for the new entry plus a NULL. */
444
 
    if (env.env_len + 2 > env.env_size) {
445
 
        env.env_size += 128;
446
 
        if (env.owned) {
447
 
            env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
448
 
        } else {
449
 
            /* We don't own env.envp, allocate a new one. */
450
 
            ep = emalloc2(env.env_size, sizeof(char *));
451
 
            memcpy(ep, env.envp, env.env_size * sizeof(char *));
452
 
            env.envp = ep;
453
 
            env.owned = TRUE;
454
 
        }
455
 
#ifdef ENV_DEBUG
456
 
        memset(env.envp + env.env_len, 0,
457
 
            (env.env_size - env.env_len) * sizeof(char *));
458
 
#endif
459
 
    }
460
 
 
461
 
#ifdef ENV_DEBUG
462
 
    if (env.envp[env.env_len] != NULL)
463
 
        errorx(1, "sudo_putenv: corrupted envp, len mismatch");
464
 
#endif
465
 
 
466
 
    if (dupcheck) {
467
 
        len = (strchr(str, '=') - str) + 1;
468
 
        for (ep = env.envp; !found && *ep != NULL; ep++) {
469
 
            if (strncmp(str, *ep, len) == 0) {
470
 
                if (overwrite)
471
 
                    *ep = str;
472
 
                found = TRUE;
473
 
            }
474
 
        }
475
 
        /* Prune out duplicate variables. */
476
 
        if (found && overwrite) {
477
 
            while (*ep != NULL) {
478
 
                if (strncmp(str, *ep, len) == 0) {
479
 
                    char **cur = ep;
480
 
                    while ((*cur = *(cur + 1)) != NULL)
481
 
                        cur++;
482
 
                } else {
483
 
                    ep++;
484
 
                }
485
 
            }
486
 
            env.env_len = ep - env.envp;
487
 
        }
488
 
    }
489
 
 
490
 
    if (!found) {
491
 
        ep = env.envp + env.env_len;
492
 
        env.env_len++;
493
 
        *ep++ = str;
494
 
        *ep = NULL;
495
 
    }
496
 
}
497
 
 
498
 
/*
499
 
 * Check the env_delete blacklist.
500
 
 * Returns TRUE if the variable was found, else false.
501
 
 */
502
 
static int
503
 
matches_env_delete(var)
504
 
    const char *var;
505
 
{
506
 
    struct list_member *cur;
507
 
    size_t len;
508
 
    int iswild, match = FALSE;
509
 
 
510
 
    /* Skip anything listed in env_delete. */
511
 
    for (cur = def_env_delete; cur; cur = cur->next) {
512
 
        len = strlen(cur->value);
513
 
        /* Deal with '*' wildcard */
514
 
        if (cur->value[len - 1] == '*') {
515
 
            len--;
516
 
            iswild = TRUE;
517
 
        } else
518
 
            iswild = FALSE;
519
 
        if (strncmp(cur->value, var, len) == 0 &&
520
 
            (iswild || var[len] == '=')) {
521
 
            match = TRUE;
522
 
            break;
523
 
        }
524
 
    }
525
 
    return(match);
526
 
}
527
 
 
528
 
/*
529
 
 * Apply the env_check list.
530
 
 * Returns TRUE if the variable is allowed, FALSE if denied
531
 
 * or -1 if no match.
532
 
 */
533
 
static int
534
 
matches_env_check(var)
535
 
    const char *var;
536
 
{
537
 
    struct list_member *cur;
538
 
    size_t len;
539
 
    int iswild, keepit = -1;
540
 
 
541
 
    for (cur = def_env_check; cur; cur = cur->next) {
542
 
        len = strlen(cur->value);
543
 
        /* Deal with '*' wildcard */
544
 
        if (cur->value[len - 1] == '*') {
545
 
            len--;
546
 
            iswild = TRUE;
547
 
        } else
548
 
            iswild = FALSE;
549
 
        if (strncmp(cur->value, var, len) == 0 &&
550
 
            (iswild || var[len] == '=')) {
551
 
            keepit = !strpbrk(var, "/%");
552
 
            break;
553
 
        }
554
 
    }
555
 
    return(keepit);
556
 
}
557
 
 
558
 
/*
559
 
 * Check the env_keep list.
560
 
 * Returns TRUE if the variable is allowed else FALSE.
561
 
 */
562
 
static int
563
 
matches_env_keep(var)
564
 
    const char *var;
565
 
{
566
 
    struct list_member *cur;
567
 
    size_t len;
568
 
    int iswild, keepit = FALSE;
569
 
 
570
 
    for (cur = def_env_keep; cur; cur = cur->next) {
571
 
        len = strlen(cur->value);
572
 
        /* Deal with '*' wildcard */
573
 
        if (cur->value[len - 1] == '*') {
574
 
            len--;
575
 
            iswild = TRUE;
576
 
        } else
577
 
            iswild = FALSE;
578
 
        if (strncmp(cur->value, var, len) == 0 &&
579
 
            (iswild || var[len] == '=')) {
580
 
            keepit = TRUE;
581
 
            break;
582
 
        }
583
 
    }
584
 
    return(keepit);
585
 
}
586
 
 
587
 
/*
588
 
 * Build a new environment and ether clear potentially dangerous
589
 
 * variables from the old one or start with a clean slate.
590
 
 * Also adds sudo-specific variables (SUDO_*).
591
 
 */
592
 
void
593
 
rebuild_env(noexec)
594
 
    int noexec;
595
 
{
596
 
    char **old_envp, **ep, *cp, *ps1;
597
 
    char idbuf[MAX_UID_T_LEN];
598
 
    unsigned int didvar;
599
 
    int reset_home = FALSE;
600
 
 
601
 
    /*
602
 
     * Either clean out the environment or reset to a safe default.
603
 
     */
604
 
    ps1 = NULL;
605
 
    didvar = 0;
606
 
    env.env_len = 0;
607
 
    env.env_size = 128;
608
 
    old_envp = env.envp;
609
 
    env.envp = emalloc2(env.env_size, sizeof(char *));
610
 
#ifdef ENV_DEBUG
611
 
    memset(env.envp, 0, env.env_size * sizeof(char *));
612
 
#endif
613
 
    if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
614
 
        /* Reset HOME based on target user unless keeping old value. */
615
 
        reset_home = TRUE;
616
 
 
617
 
        /* Pull in vars we want to keep from the old environment. */
618
 
        for (ep = old_envp; *ep; ep++) {
619
 
            int keepit;
620
 
 
621
 
            /* Skip variables with values beginning with () (bash functions) */
622
 
            if ((cp = strchr(*ep, '=')) != NULL) {
623
 
                if (strncmp(cp, "=() ", 3) == 0)
624
 
                    continue;
625
 
            }
626
 
 
627
 
            /*
628
 
             * First check certain variables for '%' and '/' characters.
629
 
             * If no match there, check the keep list.
630
 
             * If nothing matched, we remove it from the environment.
631
 
             */
632
 
            keepit = matches_env_check(*ep);
633
 
            if (keepit == -1)
634
 
                keepit = matches_env_keep(*ep);
635
 
 
636
 
            if (!strncmp (*ep, "DISPLAY=",8)
637
 
                || !strncmp (*ep, "XAUTHORITY=", 11)
638
 
                || !strncmp (*ep, "XAUTHORIZATION=", 15)
639
 
                || !strncmp (*ep, "XAPPLRESDIR=", 12)
640
 
                || !strncmp (*ep, "XFILESEARCHPATH=", 16)
641
 
                || !strncmp (*ep, "XUSERFILESEARCHPATH=", 20)
642
 
                || !strncmp (*ep, "LANG=", 5)
643
 
                || !strncmp (*ep, "LANGUAGE=", 9)
644
 
                || !strncmp (*ep, "LC_", 3))
645
 
              keepit = 1;
646
 
 
647
 
            /* For SUDO_PS1 -> PS1 conversion. */
648
 
            if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
649
 
                ps1 = *ep + 5;
650
 
 
651
 
            if (keepit) {
652
 
                /* Preserve variable. */
653
 
                switch (**ep) {
654
 
                    case 'H':
655
 
                        if (strncmp(*ep, "HOME=", 5) == 0)
656
 
                            SET(didvar, DID_HOME);
657
 
                        break;
658
 
                    case 'L':
659
 
                        if (strncmp(*ep, "LOGNAME=", 8) == 0)
660
 
                            SET(didvar, DID_LOGNAME);
661
 
                        break;
662
 
                    case 'M':
663
 
                        if (strncmp(*ep, "MAIL=", 5) == 0)
664
 
                            SET(didvar, DID_MAIL);
665
 
                        break;
666
 
                    case 'P':
667
 
                        if (strncmp(*ep, "PATH=", 5) == 0)
668
 
                            SET(didvar, DID_PATH);
669
 
                        break;
670
 
                    case 'S':
671
 
                        if (strncmp(*ep, "SHELL=", 6) == 0)
672
 
                            SET(didvar, DID_SHELL);
673
 
                        break;
674
 
                    case 'T':
675
 
                        if (strncmp(*ep, "TERM=", 5) == 0)
676
 
                            SET(didvar, DID_TERM);
677
 
                        break;
678
 
                    case 'U':
679
 
                        if (strncmp(*ep, "USER=", 5) == 0)
680
 
                            SET(didvar, DID_USER);
681
 
                        if (strncmp(*ep, "USERNAME=", 5) == 0)
682
 
                            SET(didvar, DID_USERNAME);
683
 
                        break;
684
 
                }
685
 
                sudo_putenv(*ep, FALSE, FALSE);
686
 
            }
687
 
        }
688
 
        didvar |= didvar << 8;          /* convert DID_* to KEPT_* */
689
 
 
690
 
        /*
691
 
         * Add in defaults.  In -i mode these come from the runas user,
692
 
         * otherwise they may be from the user's environment (depends
693
 
         * on sudoers options).
694
 
         */
695
 
        if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
696
 
            sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
697
 
            sudo_setenv("LOGNAME", runas_pw->pw_name,
698
 
                ISSET(didvar, DID_LOGNAME));
699
 
            sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER));
700
 
            sudo_setenv("USERNAME", runas_pw->pw_name,
701
 
                ISSET(didvar, DID_USERNAME));
702
 
        } else {
703
 
            if (!ISSET(didvar, DID_SHELL))
704
 
                sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
705
 
            if (!ISSET(didvar, DID_LOGNAME))
706
 
                sudo_setenv("LOGNAME", user_name, FALSE);
707
 
            if (!ISSET(didvar, DID_USER))
708
 
                sudo_setenv("USER", user_name, FALSE);
709
 
            if (!ISSET(didvar, DID_USERNAME))
710
 
                sudo_setenv("USERNAME", user_name, FALSE);
711
 
        }
712
 
        /*
713
 
         * Set MAIL to target user in -i mode or if MAIL is not preserved
714
 
         * from user's environment.
715
 
         */
716
 
        if (ISSET(sudo_mode, MODE_LOGIN_SHELL) || !ISSET(didvar, KEPT_MAIL)) {
717
 
            cp = _PATH_MAILDIR;
718
 
            if (cp[sizeof(_PATH_MAILDIR) - 2] == '/')
719
 
                easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name);
720
 
            else
721
 
                easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name);
722
 
            sudo_putenv(cp, ISSET(didvar, DID_MAIL), TRUE);
723
 
        }
724
 
    } else {
725
 
        /* Reset HOME based on target user if configured to. */
726
 
        if (ISSET(sudo_mode, MODE_RUN)) {
727
 
            if (def_always_set_home || ISSET(sudo_mode, MODE_RESET_HOME) || 
728
 
                (ISSET(sudo_mode, MODE_SHELL) && def_set_home))
729
 
                reset_home = TRUE;
730
 
        }
731
 
 
732
 
        /*
733
 
         * Copy environ entries as long as they don't match env_delete or
734
 
         * env_check.
735
 
         */
736
 
        for (ep = old_envp; *ep; ep++) {
737
 
            int okvar;
738
 
 
739
 
            /* Skip variables with values beginning with () (bash functions) */
740
 
            if ((cp = strchr(*ep, '=')) != NULL) {
741
 
                if (strncmp(cp, "=() ", 3) == 0)
742
 
                    continue;
743
 
            }
744
 
 
745
 
            /*
746
 
             * First check variables against the blacklist in env_delete.
747
 
             * If no match there check for '%' and '/' characters.
748
 
             */
749
 
            okvar = matches_env_delete(*ep) != TRUE;
750
 
            if (okvar)
751
 
                okvar = matches_env_check(*ep) != FALSE;
752
 
 
753
 
            if (okvar) {
754
 
                if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
755
 
                    ps1 = *ep + 5;
756
 
                else if (strncmp(*ep, "PATH=", 5) == 0)
757
 
                    SET(didvar, DID_PATH);
758
 
                else if (strncmp(*ep, "TERM=", 5) == 0)
759
 
                    SET(didvar, DID_TERM);
760
 
                sudo_putenv(*ep, FALSE, FALSE);
761
 
            }
762
 
        }
763
 
    }
764
 
    /* Replace the PATH envariable with a secure one? */
765
 
    if (def_secure_path && !user_is_exempt()) {
766
 
        sudo_setenv("PATH", def_secure_path, TRUE);
767
 
        SET(didvar, DID_PATH);
768
 
    }
769
 
 
770
 
    /* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */
771
 
    if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
772
 
        if (!ISSET(didvar, KEPT_LOGNAME))
773
 
            sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
774
 
        if (!ISSET(didvar, KEPT_USER))
775
 
            sudo_setenv("USER", runas_pw->pw_name, TRUE);
776
 
        if (!ISSET(didvar, KEPT_USERNAME))
777
 
            sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
778
 
    }
779
 
 
780
 
    /* Set $HOME to target user if not preserving user's value. */
781
 
    if (reset_home && !ISSET(didvar, KEPT_HOME))
782
 
        sudo_setenv("HOME", runas_pw->pw_dir, TRUE);
783
 
 
784
 
    /* Provide default values for $TERM and $PATH if they are not set. */
785
 
    if (!ISSET(didvar, DID_TERM))
786
 
        sudo_putenv("TERM=unknown", FALSE, FALSE);
787
 
    if (!ISSET(didvar, DID_PATH))
788
 
        sudo_setenv("PATH", _PATH_STDPATH, FALSE);
789
 
 
790
 
    /*
791
 
     * Preload a noexec file?  For a list of LD_PRELOAD-alikes, see
792
 
     * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
793
 
     * XXX - should prepend to original value, if any
794
 
     */
795
 
    if (noexec && def_noexec_file != NULL) {
796
 
#if defined(__darwin__) || defined(__APPLE__)
797
 
        sudo_setenv("DYLD_INSERT_LIBRARIES", def_noexec_file, TRUE);
798
 
        sudo_setenv("DYLD_FORCE_FLAT_NAMESPACE", "", TRUE);
799
 
#else
800
 
# if defined(__osf__) || defined(__sgi)
801
 
        easprintf(&cp, "%s:DEFAULT", def_noexec_file);
802
 
        sudo_setenv("_RLD_LIST", cp, TRUE);
803
 
        efree(cp);
804
 
# else
805
 
#  ifdef _AIX
806
 
        sudo_setenv("LDR_PRELOAD", def_noexec_file, TRUE);
807
 
#  else
808
 
        sudo_setenv("LD_PRELOAD", def_noexec_file, TRUE);
809
 
#  endif /* _AIX */
810
 
# endif /* __osf__ || __sgi */
811
 
#endif /* __darwin__ || __APPLE__ */
812
 
    }
813
 
 
814
 
    /* Set PS1 if SUDO_PS1 is set. */
815
 
    if (ps1 != NULL)
816
 
        sudo_putenv(ps1, TRUE, TRUE);
817
 
 
818
 
    /* Add the SUDO_COMMAND envariable (cmnd + args). */
819
 
    if (user_args) {
820
 
        easprintf(&cp, "%s %s", user_cmnd, user_args);
821
 
        sudo_setenv("SUDO_COMMAND", cp, TRUE);
822
 
        efree(cp);
823
 
    } else {
824
 
        sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE);
825
 
    }
826
 
 
827
 
    /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
828
 
    sudo_setenv("SUDO_USER", user_name, TRUE);
829
 
    snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_uid);
830
 
    sudo_setenv("SUDO_UID", idbuf, TRUE);
831
 
    snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_gid);
832
 
    sudo_setenv("SUDO_GID", idbuf, TRUE);
833
 
 
834
 
    /* Free old environment. */
835
 
    efree(old_envp);
836
 
}
837
 
 
838
 
void
839
 
insert_env_vars(env_vars)
840
 
    struct list_member *env_vars;
841
 
{
842
 
    struct list_member *cur;
843
 
 
844
 
    /* Add user-specified environment variables. */
845
 
    for (cur = env_vars; cur != NULL; cur = cur->next)
846
 
        putenv(cur->value);
847
 
}
848
 
 
849
 
/*
850
 
 * Validate the list of environment variables passed in on the command
851
 
 * line against env_delete, env_check, and env_keep.
852
 
 * Calls log_error() if any specified variables are not allowed.
853
 
 */
854
 
void
855
 
validate_env_vars(env_vars)
856
 
    struct list_member *env_vars;
857
 
{
858
 
    struct list_member *var;
859
 
    char *eq, *bad = NULL;
860
 
    size_t len, blen = 0, bsize = 0;
861
 
    int okvar;
862
 
 
863
 
    /* Add user-specified environment variables. */
864
 
    for (var = env_vars; var != NULL; var = var->next) {
865
 
        if (def_secure_path && !user_is_exempt() &&
866
 
            strncmp(var->value, "PATH=", 5) == 0) {
867
 
            okvar = FALSE;
868
 
        } else if (def_env_reset) {
869
 
            okvar = matches_env_check(var->value);
870
 
            if (okvar == -1)
871
 
                okvar = matches_env_keep(var->value);
872
 
        } else {
873
 
            okvar = matches_env_delete(var->value) == FALSE;
874
 
            if (okvar == FALSE)
875
 
                okvar = matches_env_check(var->value) != FALSE;
876
 
        }
877
 
        if (okvar == FALSE) {
878
 
            /* Not allowed, add to error string, allocating as needed. */
879
 
            if ((eq = strchr(var->value, '=')) != NULL)
880
 
                *eq = '\0';
881
 
            len = strlen(var->value) + 2;
882
 
            if (blen + len >= bsize) {
883
 
                do {
884
 
                    bsize += 1024;
885
 
                } while (blen + len >= bsize);
886
 
                bad = erealloc(bad, bsize);
887
 
                bad[blen] = '\0';
888
 
            }
889
 
            strlcat(bad, var->value, bsize);
890
 
            strlcat(bad, ", ", bsize);
891
 
            blen += len;
892
 
            if (eq != NULL)
893
 
                *eq = '=';
894
 
        }
895
 
    }
896
 
    if (bad != NULL) {
897
 
        bad[blen - 2] = '\0';           /* remove trailing ", " */
898
 
        log_error(NO_MAIL,
899
 
            "sorry, you are not allowed to set the following environment variables: %s", bad);
900
 
        /* NOTREACHED */
901
 
        efree(bad);
902
 
    }
903
 
}
904
 
 
905
 
/*
906
 
 * Read in /etc/environment ala AIX and Linux.
907
 
 * Lines may be in either of three formats:
908
 
 *  NAME=VALUE
909
 
 *  NAME="VALUE"
910
 
 *  NAME='VALUE'
911
 
 * with an optional "export" prefix so the shell can source the file.
912
 
 * Invalid lines, blank lines, or lines consisting solely of a comment
913
 
 * character are skipped.
914
 
 */
915
 
void
916
 
read_env_file(path, overwrite)
917
 
    const char *path;
918
 
    int overwrite;
919
 
{
920
 
    FILE *fp;
921
 
    char *cp, *var, *val;
922
 
    size_t var_len, val_len;
923
 
 
924
 
    if ((fp = fopen(path, "r")) == NULL)
925
 
        return;
926
 
 
927
 
    while ((var = sudo_parseln(fp)) != NULL) {
928
 
        /* Skip blank or comment lines */
929
 
        if (*var == '\0')
930
 
            continue;
931
 
 
932
 
        /* Skip optional "export " */
933
 
        if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) {
934
 
            var += 7;
935
 
            while (isspace((unsigned char) *var)) {
936
 
                var++;
937
 
            }
938
 
        }
939
 
 
940
 
        /* Must be of the form name=["']value['"] */
941
 
        for (val = var; *val != '\0' && *val != '='; val++)
942
 
            ;
943
 
        if (var == val || *val != '=')
944
 
            continue;
945
 
        var_len = (size_t)(val - var);
946
 
        val_len = strlen(++val);
947
 
 
948
 
        /* Strip leading and trailing single/double quotes */
949
 
        if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
950
 
            val[val_len - 1] = '\0';
951
 
            val++;
952
 
            val_len -= 2;
953
 
        }
954
 
 
955
 
        cp = emalloc(var_len + 1 + val_len + 1);
956
 
        memcpy(cp, var, var_len + 1); /* includes '=' */
957
 
        memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
958
 
 
959
 
        sudo_putenv(cp, TRUE, overwrite);
960
 
    }
961
 
    fclose(fp);
962
 
}
963
 
 
964
 
void
965
 
init_envtables()
966
 
{
967
 
    struct list_member *cur;
968
 
    const char **p;
969
 
 
970
 
    /* Fill in the "env_delete" list. */
971
 
    for (p = initial_badenv_table; *p; p++) {
972
 
        cur = emalloc(sizeof(struct list_member));
973
 
        cur->value = estrdup(*p);
974
 
        cur->next = def_env_delete;
975
 
        def_env_delete = cur;
976
 
    }
977
 
 
978
 
    /* Fill in the "env_check" list. */
979
 
    for (p = initial_checkenv_table; *p; p++) {
980
 
        cur = emalloc(sizeof(struct list_member));
981
 
        cur->value = estrdup(*p);
982
 
        cur->next = def_env_check;
983
 
        def_env_check = cur;
984
 
    }
985
 
 
986
 
    /* Fill in the "env_keep" list. */
987
 
    for (p = initial_keepenv_table; *p; p++) {
988
 
        cur = emalloc(sizeof(struct list_member));
989
 
        cur->value = estrdup(*p);
990
 
        cur->next = def_env_keep;
991
 
        def_env_keep = cur;
992
 
    }
993
 
}