mirror of
https://github.com/slicer69/doas
synced 2024-10-01 13:43:37 +00:00
On some platforms (seemingly Linux and macOS) it is possible for
repeated calls to getpwuid() can over-write the original struct passwd strucuture. This can lead to the original user's environment data being overwritten by the target user's, even when "keepenv" is specified in the doas.conf file. We now do a deep copy of the original and target users' struct passwd information to avoid over-writting the original on platforms where libc uses a static area for all calls.
This commit is contained in:
parent
f88bb2e8c4
commit
a006f46031
9
doas.c
9
doas.c
|
@ -279,7 +279,7 @@ main(int argc, char **argv)
|
|||
const char *cmd;
|
||||
char cmdline[LINE_MAX];
|
||||
char myname[_PW_NAME_LEN + 1];
|
||||
struct passwd *original_pw, *target_pw;
|
||||
struct passwd *original_pw, *target_pw, *temp_pw;
|
||||
struct rule *rule;
|
||||
uid_t uid;
|
||||
uid_t target = 0;
|
||||
|
@ -341,7 +341,8 @@ main(int argc, char **argv)
|
|||
} else if ((!sflag && !argc) || (sflag && argc))
|
||||
usage();
|
||||
|
||||
original_pw = getpwuid(uid);
|
||||
temp_pw = getpwuid(uid);
|
||||
original_pw = copyenvpw(temp_pw);
|
||||
if (! original_pw)
|
||||
err(1, "getpwuid failed");
|
||||
if (strlcpy(myname, original_pw->pw_name, sizeof(myname)) >= sizeof(myname))
|
||||
|
@ -505,10 +506,12 @@ main(int argc, char **argv)
|
|||
if (pledge("stdio rpath getpw exec id", NULL) == -1)
|
||||
err(1, "pledge");
|
||||
*/
|
||||
target_pw = getpwuid(target);
|
||||
temp_pw = getpwuid(target);
|
||||
target_pw = copyenvpw(temp_pw);
|
||||
if (! target_pw)
|
||||
errx(1, "no passwd entry for target");
|
||||
|
||||
|
||||
#if defined(HAVE_LOGIN_CAP_H)
|
||||
if (setusercontext(NULL, target_pw, target, LOGIN_SETGROUP |
|
||||
LOGIN_SETPRIORITY | LOGIN_SETRESOURCES | LOGIN_SETUMASK |
|
||||
|
|
1
doas.h
1
doas.h
|
@ -31,6 +31,7 @@ extern int parse_errors;
|
|||
|
||||
struct passwd;
|
||||
char **prepenv(struct rule *, struct passwd *original, struct passwd *target);
|
||||
struct passwd *copyenvpw(struct passwd *original);
|
||||
|
||||
#ifndef GLOBAL_PATH
|
||||
#define GLOBAL_PATH "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
|
31
env.c
31
env.c
|
@ -83,6 +83,32 @@ addnode(struct env *env, const char *key, const char *value)
|
|||
}
|
||||
|
||||
|
||||
/* Copy an original (possibly static in memory) password structure.
|
||||
Make a deep copy of it so that our original andtarget do not overlap
|
||||
on future calls.
|
||||
*/
|
||||
struct passwd *
|
||||
copyenvpw(struct passwd *my_static)
|
||||
{
|
||||
struct passwd *new_pw;
|
||||
|
||||
if (! my_static)
|
||||
return NULL;
|
||||
new_pw = (struct passwd *) calloc(1, sizeof(struct passwd));
|
||||
if (! new_pw)
|
||||
return NULL;
|
||||
|
||||
new_pw->pw_name = strdup(my_static->pw_name);
|
||||
new_pw->pw_passwd = strdup(my_static->pw_passwd);
|
||||
new_pw->pw_uid = my_static->pw_uid;
|
||||
new_pw->pw_gid = my_static->pw_gid;
|
||||
new_pw->pw_gecos = strdup(my_static->pw_gecos);
|
||||
new_pw->pw_dir = strdup(my_static->pw_dir);
|
||||
new_pw->pw_shell = strdup(my_static->pw_shell);
|
||||
return new_pw;
|
||||
}
|
||||
|
||||
|
||||
static struct env *
|
||||
createenv(struct rule *rule, struct passwd *original, struct passwd *target)
|
||||
{
|
||||
|
@ -96,7 +122,10 @@ createenv(struct rule *rule, struct passwd *original, struct passwd *target)
|
|||
env->count = 0;
|
||||
|
||||
addnode(env, "DOAS_USER", original->pw_name);
|
||||
addnode(env, "HOME", target->pw_dir);
|
||||
if (rule->options & KEEPENV)
|
||||
addnode(env, "HOME", original->pw_dir);
|
||||
else
|
||||
addnode(env, "HOME", target->pw_dir);
|
||||
addnode(env, "LOGNAME", target->pw_name);
|
||||
addnode(env, "PATH", GLOBAL_PATH);
|
||||
addnode(env, "SHELL", target->pw_shell);
|
||||
|
|
Loading…
Reference in a new issue