Add simple API for to allow reading environment data from different sources.
Currently, this is used to read a file like /etc/environment.
This commit is contained in:
@@ -105,6 +105,25 @@
|
|||||||
# define KEPT_USER_VARIABLES (KEPT_LOGNAME|KEPT_USER)
|
# define KEPT_USER_VARIABLES (KEPT_LOGNAME|KEPT_USER)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions to open, close and parse an environment file, either
|
||||||
|
* a system file such as /etc/environment or one specified in sudoers.
|
||||||
|
*/
|
||||||
|
struct sudoers_env_file {
|
||||||
|
void * (*open)(const char *);
|
||||||
|
void (*close)(void *);
|
||||||
|
char * (*next)(void *, int *);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* State for a local environment file.
|
||||||
|
*/
|
||||||
|
struct env_file_local {
|
||||||
|
FILE *fp;
|
||||||
|
char *line;
|
||||||
|
size_t linesize;
|
||||||
|
};
|
||||||
|
|
||||||
struct environment {
|
struct environment {
|
||||||
char **envp; /* pointer to the new environment */
|
char **envp; /* pointer to the new environment */
|
||||||
char **old_envp; /* pointer the old environment we allocated */
|
char **old_envp; /* pointer the old environment we allocated */
|
||||||
@@ -1188,8 +1207,39 @@ validate_env_vars(char * const env_vars[])
|
|||||||
debug_return_bool(ret);
|
debug_return_bool(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
env_file_open_local(const char *path)
|
||||||
|
{
|
||||||
|
struct env_file_local *efl;
|
||||||
|
debug_decl(env_file_open_local, SUDOERS_DEBUG_ENV)
|
||||||
|
|
||||||
|
efl = calloc(1, sizeof(*efl));
|
||||||
|
if (efl != NULL) {
|
||||||
|
if ((efl->fp = fopen(path, "r")) == NULL) {
|
||||||
|
free(efl);
|
||||||
|
efl = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_return_ptr(efl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
env_file_close_local(void *cookie)
|
||||||
|
{
|
||||||
|
struct env_file_local *efl = cookie;
|
||||||
|
debug_decl(env_file_close_local, SUDOERS_DEBUG_ENV)
|
||||||
|
|
||||||
|
if (efl != NULL) {
|
||||||
|
if (efl->fp != NULL)
|
||||||
|
fclose(efl->fp);
|
||||||
|
free(efl->line);
|
||||||
|
free(efl);
|
||||||
|
}
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read in /etc/environment ala AIX and Linux.
|
* Parse /etc/environment lines ala AIX and Linux.
|
||||||
* Lines may be in either of three formats:
|
* Lines may be in either of three formats:
|
||||||
* NAME=VALUE
|
* NAME=VALUE
|
||||||
* NAME="VALUE"
|
* NAME="VALUE"
|
||||||
@@ -1198,24 +1248,24 @@ validate_env_vars(char * const env_vars[])
|
|||||||
* Invalid lines, blank lines, or lines consisting solely of a comment
|
* Invalid lines, blank lines, or lines consisting solely of a comment
|
||||||
* character are skipped.
|
* character are skipped.
|
||||||
*/
|
*/
|
||||||
bool
|
static char *
|
||||||
read_env_file(const char *path, bool overwrite, bool restricted)
|
env_file_next_local(void *cookie, int *errnum)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
struct env_file_local *efl = cookie;
|
||||||
bool ret = true;
|
char *var, *val, *ret = NULL;
|
||||||
char *cp, *var, *val, *line = NULL;
|
size_t var_len, val_len;
|
||||||
size_t var_len, val_len, linesize = 0;
|
debug_decl(env_file_next_local, SUDOERS_DEBUG_ENV)
|
||||||
debug_decl(read_env_file, SUDOERS_DEBUG_ENV)
|
|
||||||
|
|
||||||
if ((fp = fopen(path, "r")) == NULL) {
|
*errnum = 0;
|
||||||
if (errno != ENOENT)
|
for (;;) {
|
||||||
ret = false;
|
if (sudo_parseln(&efl->line, &efl->linesize, NULL, efl->fp, PARSELN_CONT_IGN) == -1) {
|
||||||
debug_return_bool(ret);
|
if (!feof(efl->fp))
|
||||||
}
|
*errnum = errno;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
while (sudo_parseln(&line, &linesize, NULL, fp, PARSELN_CONT_IGN) != -1) {
|
|
||||||
/* Skip blank or comment lines */
|
/* Skip blank or comment lines */
|
||||||
if (*(var = line) == '\0')
|
if (*(var = efl->line) == '\0')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Skip optional "export " */
|
/* Skip optional "export " */
|
||||||
@@ -1234,15 +1284,6 @@ read_env_file(const char *path, bool overwrite, bool restricted)
|
|||||||
var_len = (size_t)(val - var);
|
var_len = (size_t)(val - var);
|
||||||
val_len = strlen(++val);
|
val_len = strlen(++val);
|
||||||
|
|
||||||
/*
|
|
||||||
* If the env file is restricted, apply env_check and env_keep
|
|
||||||
* when env_reset is set or env_delete when it is not.
|
|
||||||
*/
|
|
||||||
if (restricted) {
|
|
||||||
if (def_env_reset ? !env_should_keep(var) : env_should_delete(var))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Strip leading and trailing single/double quotes */
|
/* Strip leading and trailing single/double quotes */
|
||||||
if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
|
if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
|
||||||
val[val_len - 1] = '\0';
|
val[val_len - 1] = '\0';
|
||||||
@@ -1250,25 +1291,91 @@ read_env_file(const char *path, bool overwrite, bool restricted)
|
|||||||
val_len -= 2;
|
val_len -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cp = malloc(var_len + 1 + val_len + 1)) == NULL) {
|
if ((ret = malloc(var_len + 1 + val_len + 1)) == NULL) {
|
||||||
|
*errnum = errno;
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
"unable to allocate memory");
|
"unable to allocate memory");
|
||||||
/* XXX - no undo on failure */
|
} else {
|
||||||
ret = false;
|
memcpy(ret, var, var_len + 1); /* includes '=' */
|
||||||
|
memcpy(ret + var_len + 1, val, val_len + 1); /* includes NUL */
|
||||||
|
sudoers_gc_add(GC_PTR, ret);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
debug_return_str(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sudoers_env_file env_file_sudoers = {
|
||||||
|
env_file_open_local,
|
||||||
|
env_file_close_local,
|
||||||
|
env_file_next_local
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct sudoers_env_file env_file_system = {
|
||||||
|
env_file_open_local,
|
||||||
|
env_file_close_local,
|
||||||
|
env_file_next_local
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
register_env_file(void * (*ef_open)(const char *), void (*ef_close)(void *),
|
||||||
|
char * (*ef_next)(void *, int *), bool system)
|
||||||
|
{
|
||||||
|
struct sudoers_env_file *ef = system ? &env_file_system : &env_file_sudoers;
|
||||||
|
|
||||||
|
ef->open = ef_open;
|
||||||
|
ef->close = ef_close;
|
||||||
|
ef->next = ef_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
read_env_file(const char *path, bool overwrite, bool restricted)
|
||||||
|
{
|
||||||
|
struct sudoers_env_file *ef;
|
||||||
|
bool ret = true;
|
||||||
|
char *envstr;
|
||||||
|
void *cookie;
|
||||||
|
int errnum;
|
||||||
|
debug_decl(read_env_file, SUDOERS_DEBUG_ENV)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The environment file may be handled differently depending on
|
||||||
|
* whether it is specified in sudoers or the system.
|
||||||
|
*/
|
||||||
|
if (path == def_env_file || path == def_restricted_env_file)
|
||||||
|
ef = &env_file_sudoers;
|
||||||
|
else
|
||||||
|
ef = &env_file_system;
|
||||||
|
|
||||||
|
cookie = ef->open(path);
|
||||||
|
if (cookie == NULL)
|
||||||
|
debug_return_bool(false);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
/* Keep reading until EOF or error. */
|
||||||
|
if ((envstr = ef->next(cookie, &errnum)) == NULL) {
|
||||||
|
if (errnum != 0)
|
||||||
|
ret = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
memcpy(cp, var, var_len + 1); /* includes '=' */
|
|
||||||
memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
|
|
||||||
|
|
||||||
sudoers_gc_add(GC_PTR, cp);
|
/*
|
||||||
if (sudo_putenv(cp, true, overwrite) == -1) {
|
* If the env file is restricted, apply env_check and env_keep
|
||||||
|
* when env_reset is set or env_delete when it is not.
|
||||||
|
*/
|
||||||
|
if (restricted) {
|
||||||
|
if (def_env_reset ? !env_should_keep(envstr) : env_should_delete(envstr)) {
|
||||||
|
free(envstr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sudo_putenv(envstr, true, overwrite) == -1) {
|
||||||
/* XXX - no undo on failure */
|
/* XXX - no undo on failure */
|
||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(line);
|
ef->close(cookie);
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
debug_return_bool(ret);
|
debug_return_bool(ret);
|
||||||
}
|
}
|
||||||
|
@@ -377,6 +377,7 @@ int sudoers_hook_getenv(const char *name, char **value, void *closure);
|
|||||||
int sudoers_hook_putenv(char *string, void *closure);
|
int sudoers_hook_putenv(char *string, void *closure);
|
||||||
int sudoers_hook_setenv(const char *name, const char *value, int overwrite, void *closure);
|
int sudoers_hook_setenv(const char *name, const char *value, int overwrite, void *closure);
|
||||||
int sudoers_hook_unsetenv(const char *name, void *closure);
|
int sudoers_hook_unsetenv(const char *name, void *closure);
|
||||||
|
void register_env_file(void * (*ef_open)(const char *), void (*ef_close)(void *), char * (*ef_next)(void *, int *), bool system);
|
||||||
|
|
||||||
/* env_pattern.c */
|
/* env_pattern.c */
|
||||||
bool matches_env_pattern(const char *pattern, const char *var, bool *full_match);
|
bool matches_env_pattern(const char *pattern, const char *var, bool *full_match);
|
||||||
|
Reference in New Issue
Block a user