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:
108
getspwuid.c
108
getspwuid.c
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
31
sudo.c
@@ -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) {
|
||||
|
Reference in New Issue
Block a user