2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-08-30 13:58:05 +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:
Todd C. Miller
2004-11-15 14:53:05 +00:00
parent 99158cc7ef
commit ae2e26fd2f
4 changed files with 115 additions and 42 deletions

View File

@@ -68,6 +68,7 @@
#endif /* HAVE_GETAUTHUID */
#include "sudo.h"
#include "redblack.h"
#ifndef lint
static const char rcsid[] = "$Sudo$";
@@ -79,6 +80,37 @@ static const char rcsid[] = "$Sudo$";
#if defined(HAVE_GETPRPWNAM) && defined(__alpha)
int crypt_type = INT_MAX;
#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.
@@ -162,12 +194,11 @@ sudo_getepw(pw)
/*
* 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 *
sudo_pwdup(pw, checkshadow)
sudo_pwdup(pw)
const struct passwd *pw;
int checkshadow;
{
char *cp;
const char *pw_passwd, *pw_shell;
@@ -175,7 +206,7 @@ sudo_pwdup(pw, checkshadow)
struct passwd *newpw;
/* 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. */
pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
@@ -264,12 +295,19 @@ struct passwd *
sudo_getpwuid(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)
return(NULL);
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)
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)
return(NULL);
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
@@ -307,6 +393,8 @@ sudo_setpwent()
#ifdef HAVE_GETAUTHUID
setauthent();
#endif
cache_byuid = rbcreate(cmp_byuid);
cache_byname = rbcreate(cmp_byname);
}
void
@@ -328,4 +416,8 @@ sudo_endpwent()
#ifdef HAVE_GETAUTHUID
endauthent();
#endif
rbdestroy(cache_byuid, (void (*)__P((VOID *))) free);
cache_byuid = NULL;
rbdestroy(cache_byname, NULL);
cache_byname = NULL;
}

View File

@@ -318,7 +318,7 @@ new_child(ppid, pid)
}
entry = (struct childinfo *) emalloc(sizeof(*entry));
entry->pid = pid;
entry->pw = sudo_pwdup(pw, 0);
entry->pw = pw;
entry->action = action;
entry->next = children.first;
children.first = entry;
@@ -357,7 +357,6 @@ rm_child(pid)
prev->next = cur->next;
else
children.first = cur->next;
free(cur->pw);
free(cur);
break;
}
@@ -395,16 +394,9 @@ update_child(pid, uid)
return; /* cannot happen */
if (child->pw->pw_uid != uid) {
free(child->pw);
/* lookup uid in passwd db, using a stub on failure */
if ((child->pw = sudo_getpwuid(uid)) == NULL) {
child->pw = emalloc(sizeof(struct passwd) + MAX_UID_T_LEN + 1);
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);
}
/* look up uid in passwd db, using a stub on failure */
if ((child->pw = sudo_getpwuid(uid)) == NULL)
child->pw = sudo_fakepwuid(uid);
}
}

View File

@@ -22,8 +22,8 @@ typedef int (*schandler_t)
struct childinfo;
struct listhead;
extern struct passwd *sudo_pwdup __P((const struct passwd *, int));
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,
struct str_msg_ask *, int, int *, int *));

31
sudo.c
View File

@@ -112,6 +112,7 @@ static struct passwd *get_authpw __P((void));
extern int sudo_edit __P((int, char **));
extern char **rebuild_env __P((char **, int, int));
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_getpwuid __P((uid_t));
@@ -339,12 +340,10 @@ main(argc, argv, envp)
/* XXX - causes confusion when root is not listed in sudoers */
if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) {
if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
struct passwd *pw;
struct passwd *pw;
if ((pw = sudo_getpwnam(prev_user)) != NULL) {
free(sudo_user.pw);
sudo_user.pw = pw;
}
if ((pw = sudo_getpwnam(prev_user)) != NULL)
sudo_user.pw = pw;
}
}
@@ -568,7 +567,7 @@ init_vars(sudo_mode)
log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
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);
/*
@@ -1035,18 +1034,12 @@ set_runaspw(user)
if (runas_pw != NULL) {
if (user_runas != &def_runas_default)
return(TRUE); /* don't override -u option */
free(runas_pw);
}
if (*user == '#') {
runas_pw = sudo_getpwuid(atoi(user + 1));
if (runas_pw == NULL) {
runas_pw = emalloc(sizeof(struct passwd));
(void) memset((VOID *)runas_pw, 0, sizeof(struct passwd));
runas_pw->pw_uid = atoi(user + 1);
}
if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
runas_pw = sudo_fakepwnam(user);
} else {
runas_pw = sudo_getpwnam(user);
if (runas_pw == NULL)
if ((runas_pw = sudo_getpwnam(user)) == NULL)
log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", user);
}
return(TRUE);
@@ -1063,14 +1056,10 @@ get_authpw()
struct passwd *pw;
if (def_rootpw) {
if (runas_pw->pw_uid == 0)
pw = runas_pw;
else if ((pw = sudo_getpwuid(0)) == NULL)
if ((pw = sudo_getpwuid(0)) == NULL)
log_error(0, "uid 0 does not exist in the passwd file!");
} else if (def_runaspw) {
if (strcmp(def_runas_default, *user_runas) == 0)
pw = runas_pw;
else if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
log_error(0, "user %s does not exist in the passwd file!",
def_runas_default);
} else if (def_targetpw) {