mirror of
https://github.com/sudo-project/sudo.git
synced 2025-08-31 22:35:10 +00:00
Cache passwd db entries in 2 reb-black trees; one indexed by uid,
the other by user name. The data returned from the cache should be considered read-only and is destroyed by sudo_endpwent().
This commit is contained in:
108
getspwuid.c
108
getspwuid.c
@@ -68,6 +68,7 @@
|
|||||||
#endif /* HAVE_GETAUTHUID */
|
#endif /* HAVE_GETAUTHUID */
|
||||||
|
|
||||||
#include "sudo.h"
|
#include "sudo.h"
|
||||||
|
#include "redblack.h"
|
||||||
|
|
||||||
#ifndef lint
|
#ifndef lint
|
||||||
static const char rcsid[] = "$Sudo$";
|
static const char rcsid[] = "$Sudo$";
|
||||||
@@ -79,6 +80,37 @@ static const char rcsid[] = "$Sudo$";
|
|||||||
#if defined(HAVE_GETPRPWNAM) && defined(__alpha)
|
#if defined(HAVE_GETPRPWNAM) && defined(__alpha)
|
||||||
int crypt_type = INT_MAX;
|
int crypt_type = INT_MAX;
|
||||||
#endif /* HAVE_GETPRPWNAM && __alpha */
|
#endif /* HAVE_GETPRPWNAM && __alpha */
|
||||||
|
static struct rbtree *cache_byuid;
|
||||||
|
static struct rbtree *cache_byname;
|
||||||
|
|
||||||
|
static int cmp_byuid __P((const VOID *, const VOID *));
|
||||||
|
static int cmp_byname __P((const VOID *, const VOID *));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare by uid.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
cmp_byuid(v1, v2)
|
||||||
|
const VOID *v1;
|
||||||
|
const VOID *v2;
|
||||||
|
{
|
||||||
|
const struct passwd *pw1 = (const struct passwd *) v1;
|
||||||
|
const struct passwd *pw2 = (const struct passwd *) v2;
|
||||||
|
return(pw1->pw_uid - pw2->pw_uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare by user name.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
cmp_byname(v1, v2)
|
||||||
|
const VOID *v1;
|
||||||
|
const VOID *v2;
|
||||||
|
{
|
||||||
|
const struct passwd *pw1 = (const struct passwd *) v1;
|
||||||
|
const struct passwd *pw2 = (const struct passwd *) v2;
|
||||||
|
return(strcmp(pw1->pw_name, pw2->pw_name));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return a copy of the encrypted password for the user described by pw.
|
* Return a copy of the encrypted password for the user described by pw.
|
||||||
@@ -162,12 +194,11 @@ sudo_getepw(pw)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Dynamically allocate space for a struct password and the constituent parts
|
* Dynamically allocate space for a struct password and the constituent parts
|
||||||
* that we care about. Fills in pw_passwd from shadow file if necessary.
|
* that we care about. Fills in pw_passwd from shadow file.
|
||||||
*/
|
*/
|
||||||
struct passwd *
|
struct passwd *
|
||||||
sudo_pwdup(pw, checkshadow)
|
sudo_pwdup(pw)
|
||||||
const struct passwd *pw;
|
const struct passwd *pw;
|
||||||
int checkshadow;
|
|
||||||
{
|
{
|
||||||
char *cp;
|
char *cp;
|
||||||
const char *pw_passwd, *pw_shell;
|
const char *pw_passwd, *pw_shell;
|
||||||
@@ -175,7 +206,7 @@ sudo_pwdup(pw, checkshadow)
|
|||||||
struct passwd *newpw;
|
struct passwd *newpw;
|
||||||
|
|
||||||
/* Get shadow password if available. */
|
/* Get shadow password if available. */
|
||||||
pw_passwd = checkshadow ? sudo_getepw(pw) : pw->pw_passwd;
|
pw_passwd = sudo_getepw(pw);
|
||||||
|
|
||||||
/* If shell field is empty, expand to _PATH_BSHELL. */
|
/* If shell field is empty, expand to _PATH_BSHELL. */
|
||||||
pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
|
pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
|
||||||
@@ -264,12 +295,19 @@ struct passwd *
|
|||||||
sudo_getpwuid(uid)
|
sudo_getpwuid(uid)
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
{
|
{
|
||||||
struct passwd *pw;
|
struct passwd key, *pw;
|
||||||
|
struct rbnode *node;
|
||||||
|
|
||||||
|
key.pw_uid = uid;
|
||||||
|
if ((node = rbfind(cache_byuid, &key)) != NULL)
|
||||||
|
return((struct passwd *) node->data);
|
||||||
if ((pw = getpwuid(uid)) == NULL)
|
if ((pw = getpwuid(uid)) == NULL)
|
||||||
return(NULL);
|
return(NULL);
|
||||||
else
|
else
|
||||||
return(sudo_pwdup(pw, 1));
|
pw = sudo_pwdup(pw);
|
||||||
|
rbinsert(cache_byname, (VOID *) pw);
|
||||||
|
rbinsert(cache_byuid, (VOID *) pw);
|
||||||
|
return(pw);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -280,12 +318,60 @@ struct passwd *
|
|||||||
sudo_getpwnam(name)
|
sudo_getpwnam(name)
|
||||||
const char *name;
|
const char *name;
|
||||||
{
|
{
|
||||||
struct passwd *pw;
|
struct passwd key, *pw;
|
||||||
|
struct rbnode *node;
|
||||||
|
|
||||||
|
key.pw_name = (char *) name;
|
||||||
|
if ((node = rbfind(cache_byname, &key)) != NULL)
|
||||||
|
return((struct passwd *) node->data);
|
||||||
if ((pw = getpwnam(name)) == NULL)
|
if ((pw = getpwnam(name)) == NULL)
|
||||||
return(NULL);
|
return(NULL);
|
||||||
else
|
else
|
||||||
return(sudo_pwdup(pw, 1));
|
pw = sudo_pwdup(pw);
|
||||||
|
rbinsert(cache_byname, (VOID *) pw);
|
||||||
|
rbinsert(cache_byuid, (VOID *) pw);
|
||||||
|
return(pw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Take a uid and return a faked up passwd struct.
|
||||||
|
*/
|
||||||
|
struct passwd *
|
||||||
|
sudo_fakepwuid(uid)
|
||||||
|
uid_t uid;
|
||||||
|
{
|
||||||
|
struct passwd *pw;
|
||||||
|
|
||||||
|
pw = emalloc(sizeof(struct passwd) + MAX_UID_T_LEN + 1);
|
||||||
|
memset(pw, 0, sizeof(struct passwd));
|
||||||
|
pw->pw_uid = uid;
|
||||||
|
pw->pw_name = (char *)pw + sizeof(struct passwd);
|
||||||
|
(void) snprintf(pw->pw_name, MAX_UID_T_LEN + 1, "#%lu",
|
||||||
|
(unsigned long) uid);
|
||||||
|
rbinsert(cache_byname, (VOID *) pw);
|
||||||
|
rbinsert(cache_byuid, (VOID *) pw);
|
||||||
|
return(pw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Take a uid in string form "#123" and return a faked up passwd struct.
|
||||||
|
*/
|
||||||
|
struct passwd *
|
||||||
|
sudo_fakepwnam(user)
|
||||||
|
char *user;
|
||||||
|
{
|
||||||
|
struct passwd *pw;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
len = strlen(user);
|
||||||
|
pw = emalloc(sizeof(struct passwd) + len + 1);
|
||||||
|
memset(pw, 0, sizeof(struct passwd));
|
||||||
|
pw->pw_uid = (uid_t) atoi(user + 1);
|
||||||
|
pw->pw_name = (char *)pw + sizeof(struct passwd);
|
||||||
|
strlcpy(pw->pw_name, user, len + 1);
|
||||||
|
rbinsert(cache_byname, (VOID *) pw);
|
||||||
|
rbinsert(cache_byuid, (VOID *) pw);
|
||||||
|
return(pw);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -307,6 +393,8 @@ sudo_setpwent()
|
|||||||
#ifdef HAVE_GETAUTHUID
|
#ifdef HAVE_GETAUTHUID
|
||||||
setauthent();
|
setauthent();
|
||||||
#endif
|
#endif
|
||||||
|
cache_byuid = rbcreate(cmp_byuid);
|
||||||
|
cache_byname = rbcreate(cmp_byname);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -328,4 +416,8 @@ sudo_endpwent()
|
|||||||
#ifdef HAVE_GETAUTHUID
|
#ifdef HAVE_GETAUTHUID
|
||||||
endauthent();
|
endauthent();
|
||||||
#endif
|
#endif
|
||||||
|
rbdestroy(cache_byuid, (void (*)__P((VOID *))) free);
|
||||||
|
cache_byuid = NULL;
|
||||||
|
rbdestroy(cache_byname, NULL);
|
||||||
|
cache_byname = NULL;
|
||||||
}
|
}
|
||||||
|
@@ -318,7 +318,7 @@ new_child(ppid, pid)
|
|||||||
}
|
}
|
||||||
entry = (struct childinfo *) emalloc(sizeof(*entry));
|
entry = (struct childinfo *) emalloc(sizeof(*entry));
|
||||||
entry->pid = pid;
|
entry->pid = pid;
|
||||||
entry->pw = sudo_pwdup(pw, 0);
|
entry->pw = pw;
|
||||||
entry->action = action;
|
entry->action = action;
|
||||||
entry->next = children.first;
|
entry->next = children.first;
|
||||||
children.first = entry;
|
children.first = entry;
|
||||||
@@ -357,7 +357,6 @@ rm_child(pid)
|
|||||||
prev->next = cur->next;
|
prev->next = cur->next;
|
||||||
else
|
else
|
||||||
children.first = cur->next;
|
children.first = cur->next;
|
||||||
free(cur->pw);
|
|
||||||
free(cur);
|
free(cur);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -395,16 +394,9 @@ update_child(pid, uid)
|
|||||||
return; /* cannot happen */
|
return; /* cannot happen */
|
||||||
|
|
||||||
if (child->pw->pw_uid != uid) {
|
if (child->pw->pw_uid != uid) {
|
||||||
free(child->pw);
|
|
||||||
/* look up uid in passwd db, using a stub on failure */
|
/* look up uid in passwd db, using a stub on failure */
|
||||||
if ((child->pw = sudo_getpwuid(uid)) == NULL) {
|
if ((child->pw = sudo_getpwuid(uid)) == NULL)
|
||||||
child->pw = emalloc(sizeof(struct passwd) + MAX_UID_T_LEN + 1);
|
child->pw = sudo_fakepwuid(uid);
|
||||||
memset(child->pw, 0, sizeof(struct passwd));
|
|
||||||
child->pw->pw_uid = uid;
|
|
||||||
child->pw->pw_name = (char *)child->pw + sizeof(struct passwd);
|
|
||||||
(void) snprintf(child->pw->pw_name, MAX_UID_T_LEN + 1, "%lu",
|
|
||||||
(unsigned long) uid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,8 +22,8 @@ typedef int (*schandler_t)
|
|||||||
struct childinfo;
|
struct childinfo;
|
||||||
struct listhead;
|
struct listhead;
|
||||||
|
|
||||||
extern struct passwd *sudo_pwdup __P((const struct passwd *, int));
|
|
||||||
extern struct passwd *sudo_getpwuid __P((uid_t));
|
extern struct passwd *sudo_getpwuid __P((uid_t));
|
||||||
|
extern struct passwd *sudo_fakepwuid __P((uid_t));
|
||||||
|
|
||||||
static int check_execv __P((int, pid_t, u_int16_t,
|
static int check_execv __P((int, pid_t, u_int16_t,
|
||||||
struct str_msg_ask *, int, int *, int *));
|
struct str_msg_ask *, int, int *, int *));
|
||||||
|
27
sudo.c
27
sudo.c
@@ -112,6 +112,7 @@ static struct passwd *get_authpw __P((void));
|
|||||||
extern int sudo_edit __P((int, char **));
|
extern int sudo_edit __P((int, char **));
|
||||||
extern char **rebuild_env __P((char **, int, int));
|
extern char **rebuild_env __P((char **, int, int));
|
||||||
extern char **zero_env __P((char **));
|
extern char **zero_env __P((char **));
|
||||||
|
extern struct passwd *sudo_fakepwnam __P((const char *));
|
||||||
extern struct passwd *sudo_getpwnam __P((const char *));
|
extern struct passwd *sudo_getpwnam __P((const char *));
|
||||||
extern struct passwd *sudo_getpwuid __P((uid_t));
|
extern struct passwd *sudo_getpwuid __P((uid_t));
|
||||||
|
|
||||||
@@ -341,12 +342,10 @@ main(argc, argv, envp)
|
|||||||
if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
|
if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
|
|
||||||
if ((pw = sudo_getpwnam(prev_user)) != NULL) {
|
if ((pw = sudo_getpwnam(prev_user)) != NULL)
|
||||||
free(sudo_user.pw);
|
|
||||||
sudo_user.pw = pw;
|
sudo_user.pw = pw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Build a new environment that avoids any nasty bits if we have a cmnd. */
|
/* Build a new environment that avoids any nasty bits if we have a cmnd. */
|
||||||
if (ISSET(sudo_mode, MODE_RUN))
|
if (ISSET(sudo_mode, MODE_RUN))
|
||||||
@@ -568,7 +567,7 @@ init_vars(sudo_mode)
|
|||||||
log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
|
log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
|
||||||
|
|
||||||
set_runaspw(*user_runas); /* may call log_error() */
|
set_runaspw(*user_runas); /* may call log_error() */
|
||||||
if (*user_runas[0] == '#' && runas_pw->pw_name && runas_pw->pw_name[0])
|
if (*user_runas[0] == '#' && runas_pw->pw_name[0] != '#')
|
||||||
*user_runas = estrdup(runas_pw->pw_name);
|
*user_runas = estrdup(runas_pw->pw_name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1035,18 +1034,12 @@ set_runaspw(user)
|
|||||||
if (runas_pw != NULL) {
|
if (runas_pw != NULL) {
|
||||||
if (user_runas != &def_runas_default)
|
if (user_runas != &def_runas_default)
|
||||||
return(TRUE); /* don't override -u option */
|
return(TRUE); /* don't override -u option */
|
||||||
free(runas_pw);
|
|
||||||
}
|
}
|
||||||
if (*user == '#') {
|
if (*user == '#') {
|
||||||
runas_pw = sudo_getpwuid(atoi(user + 1));
|
if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
|
||||||
if (runas_pw == NULL) {
|
runas_pw = sudo_fakepwnam(user);
|
||||||
runas_pw = emalloc(sizeof(struct passwd));
|
|
||||||
(void) memset((VOID *)runas_pw, 0, sizeof(struct passwd));
|
|
||||||
runas_pw->pw_uid = atoi(user + 1);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
runas_pw = sudo_getpwnam(user);
|
if ((runas_pw = sudo_getpwnam(user)) == NULL)
|
||||||
if (runas_pw == NULL)
|
|
||||||
log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", user);
|
log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", user);
|
||||||
}
|
}
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
@@ -1063,14 +1056,10 @@ get_authpw()
|
|||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
|
|
||||||
if (def_rootpw) {
|
if (def_rootpw) {
|
||||||
if (runas_pw->pw_uid == 0)
|
if ((pw = sudo_getpwuid(0)) == NULL)
|
||||||
pw = runas_pw;
|
|
||||||
else if ((pw = sudo_getpwuid(0)) == NULL)
|
|
||||||
log_error(0, "uid 0 does not exist in the passwd file!");
|
log_error(0, "uid 0 does not exist in the passwd file!");
|
||||||
} else if (def_runaspw) {
|
} else if (def_runaspw) {
|
||||||
if (strcmp(def_runas_default, *user_runas) == 0)
|
if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
|
||||||
pw = runas_pw;
|
|
||||||
else if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
|
|
||||||
log_error(0, "user %s does not exist in the passwd file!",
|
log_error(0, "user %s does not exist in the passwd file!",
|
||||||
def_runas_default);
|
def_runas_default);
|
||||||
} else if (def_targetpw) {
|
} else if (def_targetpw) {
|
||||||
|
Reference in New Issue
Block a user