Files
shadow/libmisc/env.c
Alejandro Colomar 09775d3718 Simplify allocation APIs
If we consider simple objects as arrays of size 1, we can considerably
simplify these APIs, merging the *ARRAY and the non-array variants.

That will produce more readable code, since lines will be shorter (by
not having ARRAY in the macro names, as all macros will consistently
handle arrays), and the allocated size will be also more explicit.

The syntax will now be of the form:

    p = MALLOC(42, foo_t);  // allocate 42 elements of type foo_t.
    p = MALLOC(1, bar_t);   // allocate 1 element of type foo_t.

The _array() allocation functions should _never_ be called directly, and
instead these macros should be used.

The non-array functions (e.g., malloc(3)) still have their place, but
are limited to allocating structures with flexible array members.  For
any other uses, the macros should be used.

Thus, we don't use any array or ARRAY variants in any code any more, and
they are only used as implementation details of these macros.

Link: <https://software.codidact.com/posts/285898/288023#answer-288023>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-06-08 09:05:39 -05:00

254 lines
5.2 KiB
C

/*
* SPDX-FileCopyrightText: 1989 - 1992, Julianne Frances Haugh
* SPDX-FileCopyrightText: 1996 - 1999, Marek Michałkiewicz
* SPDX-FileCopyrightText: 2003 - 2005, Tomasz Kłoczko
* SPDX-FileCopyrightText: 2008 - 2009, Nicolas François
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <config.h>
#ident "$Id$"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "alloc.h"
#include "prototypes.h"
#include "defines.h"
#include "shadowlog.h"
/*
* NEWENVP_STEP must be a power of two. This is the number
* of (char *) pointers to allocate at a time, to avoid using
* realloc() too often.
*/
#define NEWENVP_STEP 16
size_t newenvc = 0;
/*@null@*/char **newenvp = NULL;
static const char *const forbid[] = {
"_RLD_=",
"BASH_ENV=", /* GNU creeping featurism strikes again... */
"ENV=",
"HOME=",
"IFS=",
"KRB_CONF=",
"LD_", /* anything with the LD_ prefix */
"LIBPATH=",
"MAIL=",
"NLSPATH=",
"PATH=",
"SHELL=",
"SHLIB_PATH=",
NULL
};
/* these are allowed, but with no slashes inside
(to work around security problems in GNU gettext) */
static const char *const noslash[] = {
"LANG=",
"LANGUAGE=",
"LC_", /* anything with the LC_ prefix */
NULL
};
/*
* initenv() must be called once before using addenv().
*/
void initenv (void)
{
newenvp = XMALLOC(NEWENVP_STEP, char *);
*newenvp = NULL;
}
void addenv (const char *string, /*@null@*/const char *value)
{
char *cp, *newstring;
size_t i;
size_t n;
if (NULL != value) {
size_t len = strlen (string) + strlen (value) + 2;
int wlen;
newstring = XMALLOC(len, char);
wlen = snprintf (newstring, len, "%s=%s", string, value);
assert (wlen == (int) len -1);
} else {
newstring = xstrdup (string);
}
/*
* Search for a '=' character within the string and if none is found
* just ignore the whole string.
*/
cp = strchr (newstring, '=');
if (NULL == cp) {
free (newstring);
return;
}
n = (size_t) (cp - newstring);
/*
* If this environment variable is already set, change its value.
*/
for (i = 0; i < newenvc; i++) {
if ( (strncmp (newstring, newenvp[i], n) == 0)
&& (('=' == newenvp[i][n]) || ('\0' == newenvp[i][n]))) {
break;
}
}
if (i < newenvc) {
free (newenvp[i]);
newenvp[i] = newstring;
return;
}
/*
* Otherwise, save the new environment variable
*/
newenvp[newenvc++] = newstring;
/*
* And extend the environment if needed.
*/
/*
* Check whether newenvc is a multiple of NEWENVP_STEP.
* If so we have to resize the vector.
* the expression (newenvc & (NEWENVP_STEP - 1)) == 0
* is equal to (newenvc % NEWENVP_STEP) == 0
* as long as NEWENVP_STEP is a power of 2.
*/
if ((newenvc & (NEWENVP_STEP - 1)) == 0) {
bool update_environ;
char **__newenvp;
/*
* If the resize operation succeeds we can
* happily go on, else print a message.
*/
update_environ = (environ == newenvp);
__newenvp = REALLOC(newenvp, newenvc + NEWENVP_STEP, char *);
if (NULL != __newenvp) {
/*
* If this is our current environment, update
* environ so that it doesn't point to some
* free memory area (realloc() could move it).
*/
if (update_environ)
environ = __newenvp;
newenvp = __newenvp;
} else {
(void) fputs (_("Environment overflow\n"), log_get_logfd());
newenvc--;
free (newenvp[newenvc]);
}
}
/*
* The last entry of newenvp must be NULL
*/
newenvp[newenvc] = NULL;
}
/*
* set_env - copy command line arguments into the environment
*/
void set_env (int argc, char *const *argv)
{
int noname = 1;
char variable[1024];
char *cp;
for (; argc > 0; argc--, argv++) {
if (strlen (*argv) >= sizeof variable) {
continue; /* ignore long entries */
}
cp = strchr (*argv, '=');
if (NULL == cp) {
int wlen;
wlen = snprintf (variable, sizeof variable, "L%d", noname);
assert (wlen < (int) sizeof(variable));
noname++;
addenv (variable, *argv);
} else {
const char *const *p;
for (p = forbid; NULL != *p; p++) {
if (strncmp (*argv, *p, strlen (*p)) == 0) {
break;
}
}
if (NULL != *p) {
strncpy (variable, *argv, (size_t)(cp - *argv));
variable[cp - *argv] = '\0';
printf (_("You may not change $%s\n"),
variable);
continue;
}
addenv (*argv, NULL);
}
}
}
/*
* sanitize_env - remove some nasty environment variables
* If you fall into a total paranoia, you should call this
* function for any root-setuid program or anything the user
* might change the environment with. 99% useless as almost
* all modern Unixes will handle setuid executables properly,
* but... I feel better with that silly precaution. -j.
*/
void sanitize_env (void)
{
char **envp = environ;
const char *const *bad;
char **cur;
char **move;
for (cur = envp; NULL != *cur; cur++) {
for (bad = forbid; NULL != *bad; bad++) {
if (strncmp (*cur, *bad, strlen (*bad)) == 0) {
for (move = cur; NULL != *move; move++) {
*move = *(move + 1);
}
cur--;
break;
}
}
}
for (cur = envp; NULL != *cur; cur++) {
for (bad = noslash; NULL != *bad; bad++) {
if (strncmp (*cur, *bad, strlen (*bad)) != 0) {
continue;
}
if (strchr (*cur, '/') == NULL) {
continue; /* OK */
}
for (move = cur; NULL != *move; move++) {
*move = *(move + 1);
}
cur--;
break;
}
}
}