• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Can't trust libc not to leak enviornment variable memory, so...
2 
3 #include "toys.h"
4 
5 // In libc, populated by start code,used by getenv() and exec() and friends.
6 extern char **environ;
7 
8 // Returns the number of bytes taken by the environment variables. For use
9 // when calculating the maximum bytes of environment+argument data that can
10 // be passed to exec for find(1) and xargs(1).
environ_bytes()11 long environ_bytes()
12 {
13   long bytes = sizeof(char *);
14   char **ev;
15 
16   for (ev = environ; *ev; ev++) bytes += sizeof(char *) + strlen(*ev) + 1;
17 
18   return bytes;
19 }
20 
21 // This will clear the inherited environment if called first thing.
22 // Use this instead of envc so we keep track of what needs to be freed.
xclearenv(void)23 void xclearenv(void)
24 {
25   toys.envc = 0;
26   *environ = 0;
27 }
28 
29 // Frees entries we set earlier. Use with libc getenv but not setenv/putenv.
30 // if name has an equals and !val, act like putenv (name=val must be malloced!)
31 // if !val unset name. (Name with = and val is an error)
xsetenv(char * name,char * val)32 void xsetenv(char *name, char *val)
33 {
34   unsigned i, len, envc;
35   char *new;
36 
37   // If we haven't snapshot initial environment state yet, do so now.
38   if (!toys.envc) {
39     // envc is size +1 so even if env empty it's nonzero after initialization
40     while (environ[toys.envc++]);
41     memcpy(new = xmalloc(((toys.envc|0xff)+1)*sizeof(char *)),
42       environ, toys.envc*sizeof(char *));
43     environ = (void *)new;
44   }
45 
46   new = strchr(name, '=');
47   if (new) {
48     len = new-name;
49     if (val) error_exit("xsetenv %s to %s", name, val);
50     new = name;
51   } else {
52     len = strlen(name);
53     if (val) new = xmprintf("%s=%s", name, val);
54   }
55 
56   envc = toys.envc-1;  // compensate for size +1 above
57   for (i = 0; environ[i]; i++) {
58     // Drop old entry, freeing as appropriate. Assumes no duplicates.
59     if (!memcmp(name, environ[i], len) && environ[i][len]=='=') {
60       if (i>=envc) free(environ[i]);
61       else {
62         // move old entries down, add at end of old data
63         toys.envc = envc--;
64         for (; new ? i<envc : !!environ[i]; i++) environ[i] = environ[i+1];
65         i = envc;
66       }
67       break;
68     }
69   }
70 
71   if (!new) return;
72 
73   // resize and null terminate if expanding
74   if (!environ[i]) {
75     len = i+1;
76     if (!(len&255)) environ = xrealloc(environ, len*sizeof(char *));
77     environ[len] = 0;
78   }
79   environ[i] = new;
80 }
81 
xunsetenv(char * name)82 void xunsetenv(char *name)
83 {
84   if (strchr(name, '=')) error_exit("xunsetenv %s name has =", name);
85   xsetenv(name, 0);
86 }
87 
88 // reset environment for a user, optionally clearing most of it
reset_env(struct passwd * p,int clear)89 void reset_env(struct passwd *p, int clear)
90 {
91   int i;
92 
93   if (clear) {
94     char *s, *stuff[] = {"TERM", "DISPLAY", "COLORTERM", "XAUTHORITY"};
95 
96     for (i=0; i<ARRAY_LEN(stuff); i++)
97       stuff[i] = (s = getenv(stuff[i])) ? xmprintf("%s=%s", stuff[i], s) : 0;
98     xclearenv();
99     for (i=0; i < ARRAY_LEN(stuff); i++) if (stuff[i]) xsetenv(stuff[i], 0);
100     if (chdir(p->pw_dir)) {
101       perror_msg("chdir %s", p->pw_dir);
102       xchdir("/");
103     }
104   } else {
105     char **ev1, **ev2;
106 
107     // remove LD_*, IFS, ENV, and BASH_ENV from environment
108     for (ev1 = ev2 = environ;;) {
109       while (*ev2 && (strstart(ev2, "LD_") || strstart(ev2, "IFS=") ||
110         strstart(ev2, "ENV=") || strstart(ev2, "BASH_ENV="))) ev2++;
111       if (!(*ev1++ = *ev2++)) break;
112     }
113   }
114 
115   setenv("PATH", _PATH_DEFPATH, 1);
116   setenv("HOME", p->pw_dir, 1);
117   setenv("SHELL", p->pw_shell, 1);
118   setenv("USER", p->pw_name, 1);
119   setenv("LOGNAME", p->pw_name, 1);
120 }
121