(root)/
util-linux-2.39/
lib/
env.c
       1  /*
       2   * environ[] array cleanup code and getenv() wrappers
       3   *
       4   * No copyright is claimed.  This code is in the public domain; do with
       5   * it what you wish.
       6   */
       7  #include <stdio.h>
       8  #include <stdlib.h>
       9  #include <string.h>
      10  #ifdef HAVE_SYS_PRCTL_H
      11  #include <sys/prctl.h>
      12  #else
      13  #define PR_GET_DUMPABLE 3
      14  #endif
      15  #if (!defined(HAVE_PRCTL) && defined(linux))
      16  #include <sys/syscall.h>
      17  #endif
      18  #include <unistd.h>
      19  #include <sys/types.h>
      20  
      21  #include "env.h"
      22  #include "all-io.h"
      23  
      24  #ifndef HAVE_ENVIRON_DECL
      25  extern char **environ;
      26  #endif
      27  
      28  static char * const forbid[] = {
      29          "BASH_ENV=",    /* GNU creeping featurism strikes again... */
      30          "ENV=",
      31          "HOME=",
      32          "IFS=",
      33          "KRB_CONF=",
      34          "LD_",          /* anything with the LD_ prefix */
      35          "LIBPATH=",
      36          "MAIL=",
      37          "NLSPATH=",
      38          "PATH=",
      39          "SHELL=",
      40          "SHLIB_PATH=",
      41          (char *) 0
      42  };
      43  
      44  /* these are allowed, but with no slashes inside
      45     (to work around security problems in GNU gettext) */
      46  static char * const noslash[] = {
      47          "LANG=",
      48          "LANGUAGE=",
      49          "LC_",          /* anything with the LC_ prefix */
      50          (char *) 0
      51  };
      52  
      53  
      54  struct ul_env_list {
      55  	char *env;
      56  	struct ul_env_list *next;
      57  };
      58  
      59  /*
      60   * Saves @name env.variable to @ls, returns pointer to the new head of the list.
      61   */
      62  static struct ul_env_list *env_list_add(struct ul_env_list *ls0, const char *str)
      63  {
      64  	struct ul_env_list *ls;
      65  	char *p;
      66  	size_t sz = 0;
      67  
      68  	if (!str || !*str)
      69  		return ls0;
      70  
      71  	sz = strlen(str) + 1;
      72  	p = malloc(sizeof(struct ul_env_list) + sz);
      73  	if (!p)
      74  		return ls0;
      75  
      76  	ls = (struct ul_env_list *) p;
      77  	p += sizeof(struct ul_env_list);
      78  	memcpy(p, str, sz);
      79  	ls->env = p;
      80  
      81  	ls->next = ls0;
      82  	return ls;
      83  }
      84  
      85  /*
      86   * Use env_from_fd() to read environment from @fd.
      87   *
      88   * @fd must be /proc/<pid>/environ file.
      89  */
      90  struct ul_env_list *env_from_fd(int fd)
      91  {
      92  	char *buf = NULL, *p;
      93  	size_t rc = 0;
      94  	struct ul_env_list *ls = NULL;
      95  
      96  	if ((rc = read_all_alloc(fd, &buf)) < 1)
      97  		return NULL;
      98  	buf[rc] = '\0';
      99  	p = buf;
     100  
     101  	while (rc > 0) {
     102  		ls = env_list_add(ls, p);
     103  		p += strlen(p) + 1;
     104  		rc -= strlen(p) + 1;
     105  	}
     106  
     107  	free(buf);
     108  	return ls;
     109  }
     110  
     111  /*
     112   * Use setenv() for all stuff in @ls.
     113   *
     114   * It would be possible to use putenv(), but we want to keep @ls free()-able.
     115   */
     116  int env_list_setenv(struct ul_env_list *ls)
     117  {
     118  	int rc = 0;
     119  
     120  	while (ls && rc == 0) {
     121  		if (ls->env) {
     122  			char *val = strchr(ls->env, '=');
     123  			if (!val)
     124  				continue;
     125  			*val = '\0';
     126  			rc = setenv(ls->env, val + 1, 0);
     127  			*val = '=';
     128  		}
     129  		ls = ls->next;
     130  	}
     131  	return rc;
     132  }
     133  
     134  void env_list_free(struct ul_env_list *ls)
     135  {
     136  	while (ls) {
     137  		struct ul_env_list *x = ls;
     138  		ls = ls->next;
     139  		free(x);
     140  	}
     141  }
     142  
     143  /*
     144   * Removes unwanted variables from environ[]. If @org is not NULL than stores
     145   * unwnated variables to the list.
     146   */
     147  void __sanitize_env(struct ul_env_list **org)
     148  {
     149          char **envp = environ;
     150          char * const *bad;
     151          char **cur;
     152          int last = 0;
     153  
     154          for (cur = envp; *cur; cur++)
     155                  last++;
     156  
     157          for (cur = envp; *cur; cur++) {
     158                  for (bad = forbid; *bad; bad++) {
     159                          if (strncmp(*cur, *bad, strlen(*bad)) == 0) {
     160  				if (org)
     161  					*org = env_list_add(*org, *cur);
     162                                  last = remote_entry(envp, cur - envp, last);
     163                                  cur--;
     164                                  break;
     165                          }
     166                  }
     167          }
     168  
     169          for (cur = envp; *cur; cur++) {
     170                  for (bad = noslash; *bad; bad++) {
     171                          if (strncmp(*cur, *bad, strlen(*bad)) != 0)
     172                                  continue;
     173                          if (!strchr(*cur, '/'))
     174                                  continue;  /* OK */
     175  			if (org)
     176  				*org = env_list_add(*org, *cur);
     177                          last = remote_entry(envp, cur - envp, last);
     178                          cur--;
     179                          break;
     180                  }
     181          }
     182  }
     183  
     184  void sanitize_env(void)
     185  {
     186  	__sanitize_env(NULL);
     187  }
     188  
     189  char *safe_getenv(const char *arg)
     190  {
     191  	if ((getuid() != geteuid()) || (getgid() != getegid()))
     192  		return NULL;
     193  #ifdef HAVE_PRCTL
     194  	if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
     195  		return NULL;
     196  #else
     197  #if (defined(linux) && defined(SYS_prctl))
     198  	if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
     199  		return NULL;
     200  #endif
     201  #endif
     202  #ifdef HAVE_SECURE_GETENV
     203  return secure_getenv(arg);
     204  #elif HAVE___SECURE_GETENV
     205  	return __secure_getenv(arg);
     206  #else
     207  	return getenv(arg);
     208  #endif
     209  }
     210  
     211  #ifdef TEST_PROGRAM
     212  int main(void)
     213  {
     214  	char *const *bad;
     215  	char copy[32];
     216  	char *p;
     217  	int retval = EXIT_SUCCESS;
     218  	struct ul_env_list *removed = NULL;
     219  
     220  	for (bad = forbid; *bad; bad++) {
     221  		strcpy(copy, *bad);
     222  		p = strchr(copy, '=');
     223  		if (p)
     224  			*p = '\0';
     225  		setenv(copy, copy, 1);
     226  	}
     227  
     228  	/* removed */
     229  	__sanitize_env(&removed);
     230  
     231  	/* check removal */
     232  	for (bad = forbid; *bad; bad++) {
     233  		strcpy(copy, *bad);
     234  		p = strchr(copy, '=');
     235  		if (p)
     236  			*p = '\0';
     237  		p = getenv(copy);
     238  		if (p) {
     239  			warnx("%s was not removed", copy);
     240  			retval = EXIT_FAILURE;
     241  		}
     242  	}
     243  
     244  	/* restore removed */
     245  	env_list_setenv(removed);
     246  
     247  	/* check restore */
     248  	for (bad = forbid; *bad; bad++) {
     249  		strcpy(copy, *bad);
     250  		p = strchr(copy, '=');
     251  		if (p)
     252  			*p = '\0';
     253  		p = getenv(copy);
     254  		if (!p) {
     255  			warnx("%s was not restored", copy);
     256  			retval = EXIT_FAILURE;
     257  		}
     258  	}
     259  
     260  	env_list_free(removed);
     261  
     262  	return retval;
     263  }
     264  #endif