Implement group caching and use the passwd and group caches throughout.

This commit is contained in:
Todd C. Miller
2004-11-16 04:24:11 +00:00
parent fd46c2c3ef
commit 9846e562ad
11 changed files with 286 additions and 45 deletions

View File

@@ -283,7 +283,7 @@ user_is_exempt()
if (!def_exempt_group) if (!def_exempt_group)
return(FALSE); return(FALSE);
if (!(grp = getgrnam(def_exempt_group))) if (!(grp = sudo_getgrnam(def_exempt_group)))
return(FALSE); return(FALSE);
if (user_gid == grp->gr_gid) if (user_gid == grp->gr_gid)

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1996, 1998-2002 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@@ -46,6 +46,7 @@
# include <unistd.h> # include <unistd.h>
#endif /* HAVE_UNISTD_H */ #endif /* HAVE_UNISTD_H */
#include <pwd.h> #include <pwd.h>
#include <grp.h>
#ifdef HAVE_GETSPNAM #ifdef HAVE_GETSPNAM
# include <shadow.h> # include <shadow.h>
#endif /* HAVE_GETSPNAM */ #endif /* HAVE_GETSPNAM */
@@ -80,18 +81,20 @@ 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 *pwcache_byuid, *pwcache_byname;
static struct rbtree *cache_byname; static struct rbtree *grcache_bygid, *grcache_byname;
static int cmp_byuid __P((const VOID *, const VOID *)); static int cmp_pwuid __P((const VOID *, const VOID *));
static int cmp_byname __P((const VOID *, const VOID *)); static int cmp_pwnam __P((const VOID *, const VOID *));
static void pw_free __P((VOID *)); static void pw_free __P((VOID *));
static int cmp_grgid __P((const VOID *, const VOID *));
static int cmp_grnam __P((const VOID *, const VOID *));
/* /*
* Compare by uid. * Compare by uid.
*/ */
static int static int
cmp_byuid(v1, v2) cmp_pwuid(v1, v2)
const VOID *v1; const VOID *v1;
const VOID *v2; const VOID *v2;
{ {
@@ -104,7 +107,7 @@ cmp_byuid(v1, v2)
* Compare by user name. * Compare by user name.
*/ */
static int static int
cmp_byname(v1, v2) cmp_pwnam(v1, v2)
const VOID *v1; const VOID *v1;
const VOID *v2; const VOID *v2;
{ {
@@ -197,7 +200,7 @@ 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. * that we care about. Fills in pw_passwd from shadow file.
*/ */
struct passwd * static struct passwd *
sudo_pwdup(pw) sudo_pwdup(pw)
const struct passwd *pw; const struct passwd *pw;
{ {
@@ -300,14 +303,14 @@ sudo_getpwuid(uid)
struct rbnode *node; struct rbnode *node;
key.pw_uid = uid; key.pw_uid = uid;
if ((node = rbfind(cache_byuid, &key)) != NULL) if ((node = rbfind(pwcache_byuid, &key)) != NULL)
return((struct passwd *) node->data); return((struct passwd *) node->data);
if ((pw = getpwuid(uid)) == NULL) if ((pw = getpwuid(uid)) == NULL)
return(NULL); return(NULL);
else else
pw = sudo_pwdup(pw); pw = sudo_pwdup(pw);
rbinsert(cache_byname, (VOID *) pw); rbinsert(pwcache_byname, (VOID *) pw);
rbinsert(cache_byuid, (VOID *) pw); rbinsert(pwcache_byuid, (VOID *) pw);
return(pw); return(pw);
} }
@@ -323,14 +326,14 @@ sudo_getpwnam(name)
struct rbnode *node; struct rbnode *node;
key.pw_name = (char *) name; key.pw_name = (char *) name;
if ((node = rbfind(cache_byname, &key)) != NULL) if ((node = rbfind(pwcache_byname, &key)) != NULL)
return((struct passwd *) node->data); return((struct passwd *) node->data);
if ((pw = getpwnam(name)) == NULL) if ((pw = getpwnam(name)) == NULL)
return(NULL); return(NULL);
else else
pw = sudo_pwdup(pw); pw = sudo_pwdup(pw);
rbinsert(cache_byname, (VOID *) pw); rbinsert(pwcache_byname, (VOID *) pw);
rbinsert(cache_byuid, (VOID *) pw); rbinsert(pwcache_byuid, (VOID *) pw);
return(pw); return(pw);
} }
@@ -349,8 +352,8 @@ sudo_fakepwuid(uid)
pw->pw_name = (char *)pw + sizeof(struct passwd); pw->pw_name = (char *)pw + sizeof(struct passwd);
(void) snprintf(pw->pw_name, MAX_UID_T_LEN + 1, "#%lu", (void) snprintf(pw->pw_name, MAX_UID_T_LEN + 1, "#%lu",
(unsigned long) uid); (unsigned long) uid);
rbinsert(cache_byname, (VOID *) pw); rbinsert(pwcache_byname, (VOID *) pw);
rbinsert(cache_byuid, (VOID *) pw); rbinsert(pwcache_byuid, (VOID *) pw);
return(pw); return(pw);
} }
@@ -359,7 +362,7 @@ sudo_fakepwuid(uid)
*/ */
struct passwd * struct passwd *
sudo_fakepwnam(user) sudo_fakepwnam(user)
char *user; const char *user;
{ {
struct passwd *pw; struct passwd *pw;
size_t len; size_t len;
@@ -370,8 +373,8 @@ sudo_fakepwnam(user)
pw->pw_uid = (uid_t) atoi(user + 1); pw->pw_uid = (uid_t) atoi(user + 1);
pw->pw_name = (char *)pw + sizeof(struct passwd); pw->pw_name = (char *)pw + sizeof(struct passwd);
strlcpy(pw->pw_name, user, len + 1); strlcpy(pw->pw_name, user, len + 1);
rbinsert(cache_byname, (VOID *) pw); rbinsert(pwcache_byname, (VOID *) pw);
rbinsert(cache_byuid, (VOID *) pw); rbinsert(pwcache_byuid, (VOID *) pw);
return(pw); return(pw);
} }
@@ -394,8 +397,8 @@ sudo_setpwent()
#ifdef HAVE_GETAUTHUID #ifdef HAVE_GETAUTHUID
setauthent(); setauthent();
#endif #endif
cache_byuid = rbcreate(cmp_byuid); pwcache_byuid = rbcreate(cmp_pwuid);
cache_byname = rbcreate(cmp_byname); pwcache_byname = rbcreate(cmp_pwnam);
} }
void void
@@ -417,10 +420,10 @@ sudo_endpwent()
#ifdef HAVE_GETAUTHUID #ifdef HAVE_GETAUTHUID
endauthent(); endauthent();
#endif #endif
rbdestroy(cache_byuid, pw_free); rbdestroy(pwcache_byuid, pw_free);
cache_byuid = NULL; pwcache_byuid = NULL;
rbdestroy(cache_byname, NULL); rbdestroy(pwcache_byname, NULL);
cache_byname = NULL; pwcache_byname = NULL;
} }
static void static void
@@ -432,3 +435,152 @@ pw_free(v)
zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd)); zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd));
free(pw); free(pw);
} }
/*
* Compare by gid.
*/
static int
cmp_grgid(v1, v2)
const VOID *v1;
const VOID *v2;
{
const struct group *grp1 = (const struct group *) v1;
const struct group *grp2 = (const struct group *) v2;
return(grp1->gr_gid - grp2->gr_gid);
}
/*
* Compare by group name.
*/
static int
cmp_grnam(v1, v2)
const VOID *v1;
const VOID *v2;
{
const struct group *grp1 = (const struct group *) v1;
const struct group *grp2 = (const struct group *) v2;
return(strcmp(grp1->gr_name, grp2->gr_name));
}
void
sudo_setgrent()
{
setgrent();
grcache_bygid = rbcreate(cmp_grgid);
grcache_byname = rbcreate(cmp_grnam);
}
void
sudo_endgrent()
{
endgrent();
rbdestroy(grcache_bygid, free);
grcache_bygid = NULL;
rbdestroy(grcache_byname, NULL);
grcache_byname = NULL;
}
static struct group *
sudo_grdup(gr)
const struct group *gr;
{
char *cp;
size_t nsize, psize, csize, num, total, len;
struct group *newgr;
/* Allocate in one big chunk for easy freeing. */
nsize = psize = csize = num = 0;
total = sizeof(struct group);
if (gr->gr_name) {
nsize = strlen(gr->gr_name) + 1;
total += nsize;
}
if (gr->gr_passwd) {
psize = strlen(gr->gr_passwd) + 1;
total += psize;
}
if (gr->gr_mem) {
for (num = 0; gr->gr_mem[num] != NULL; num++)
total += strlen(gr->gr_mem[num]) + 1;
num++;
total += sizeof(char *) * num;
}
if ((cp = malloc(total)) == NULL)
return (NULL);
newgr = (struct group *)cp;
/*
* Copy in group contents and make strings relative to space
* at the end of the buffer.
*/
(void)memcpy(newgr, gr, sizeof(struct group));
cp += sizeof(struct group);
if (nsize) {
(void)memcpy(cp, gr->gr_name, nsize);
newgr->gr_name = cp;
cp += nsize;
}
if (psize) {
(void)memcpy(cp, gr->gr_passwd, psize);
newgr->gr_passwd = cp;
cp += psize;
}
if (gr->gr_mem) {
newgr->gr_mem = (char **)cp;
cp += sizeof(char *) * num;
for (num = 0; gr->gr_mem[num] != NULL; num++) {
len = strlen(gr->gr_mem[num]) + 1;
memcpy(cp, gr->gr_mem[num], len);
newgr->gr_mem[num] = cp;
cp += len;
}
newgr->gr_mem[num] = NULL;
}
return (newgr);
}
/*
* Get a group entry by gid and allocate space for it.
*/
struct group *
sudo_getgruid(gid)
gid_t gid;
{
struct group key, *gr;
struct rbnode *node;
key.gr_gid = gid;
if ((node = rbfind(grcache_bygid, &key)) != NULL)
return((struct group *) node->data);
if ((gr = getgrgid(gid)) == NULL)
return(NULL);
else
gr = sudo_grdup(gr);
rbinsert(grcache_byname, (VOID *) gr);
rbinsert(grcache_bygid, (VOID *) gr);
return(gr);
}
/*
* Get a group entry by name and allocate space for it.
*/
struct group *
sudo_getgrnam(name)
const char *name;
{
struct group key, *gr;
struct rbnode *node;
key.gr_name = (char *) name;
if ((node = rbfind(grcache_byname, &key)) != NULL)
return((struct group *) node->data);
if ((gr = getgrnam(name)) == NULL)
return(NULL);
else
gr = sudo_grdup(gr);
rbinsert(grcache_byname, (VOID *) gr);
rbinsert(grcache_bygid, (VOID *) gr);
return(gr);
}

7
glob.c
View File

@@ -172,6 +172,9 @@ static int match __P((Char *, Char *, Char *));
static void qprintf __P((const char *, Char *)); static void qprintf __P((const char *, Char *));
#endif #endif
extern struct passwd *sudo_getpwnam __P((const char *));
extern struct passwd *sudo_getpwuid __P((uid_t));
int int
glob(pattern, flags, errfunc, pglob) glob(pattern, flags, errfunc, pglob)
const char *pattern; const char *pattern;
@@ -385,7 +388,7 @@ globtilde(pattern, patbuf, patbuf_len, pglob)
* first and then trying the password file * first and then trying the password file
*/ */
if ((h = getenv("HOME")) == NULL) { if ((h = getenv("HOME")) == NULL) {
if ((pwd = getpwuid(getuid())) == NULL) if ((pwd = sudo_getpwuid(getuid())) == NULL)
return pattern; return pattern;
else else
h = pwd->pw_dir; h = pwd->pw_dir;
@@ -394,7 +397,7 @@ globtilde(pattern, patbuf, patbuf_len, pglob)
/* /*
* Expand a ~user * Expand a ~user
*/ */
if ((pwd = getpwnam((char*) patbuf)) == NULL) if ((pwd = sudo_getpwnam((char*) patbuf)) == NULL)
return pattern; return pattern;
else else
h = pwd->pw_dir; h = pwd->pw_dir;

4
ldap.c
View File

@@ -440,7 +440,7 @@ sudo_ldap_build_pass1()
ncat(&b,&sz,")"); ncat(&b,&sz,")");
/* Append primary group */ /* Append primary group */
grp=getgrgid(getgid()); grp=sudo_getgrgid(getgid());
if (grp!=NULL){ if (grp!=NULL){
ncat(&b,&sz,"(sudoUser=%"); ncat(&b,&sz,"(sudoUser=%");
ncat(&b,&sz,grp->gr_name); ncat(&b,&sz,grp->gr_name);
@@ -452,7 +452,7 @@ sudo_ldap_build_pass1()
grplist=calloc(ngrps,sizeof(gid_t)); grplist=calloc(ngrps,sizeof(gid_t));
if (grplist!=NULL && (0<getgroups(ngrps,grplist))) if (grplist!=NULL && (0<getgroups(ngrps,grplist)))
for(i=0;i<ngrps;i++){ for(i=0;i<ngrps;i++){
if((grp=getgrgid(grplist[i]))!=NULL){ if((grp=sudo_getgrgid(grplist[i]))!=NULL){
ncat(&b,&sz,"(sudoUser=%"); ncat(&b,&sz,"(sudoUser=%");
ncat(&b,&sz,grp->gr_name); ncat(&b,&sz,grp->gr_name);
ncat(&b,&sz,")"); ncat(&b,&sz,")");

View File

@@ -492,7 +492,7 @@ send_mail(line)
/* Close password and group files so we don't leak fds. */ /* Close password and group files so we don't leak fds. */
sudo_endpwent(); sudo_endpwent();
endgrent(); sudo_endgrent();
/* /*
* Depending on the config, either run the mailer as root * Depending on the config, either run the mailer as root

14
match.c
View File

@@ -528,7 +528,7 @@ userpw_matches(sudoers_user, user, pw)
/* /*
* Returns TRUE if the given user belongs to the named group, * Returns TRUE if the given user belongs to the named group,
* else returns FALSE. * else returns FALSE.
* XXX - reduce the number of passwd/group lookups * XXX - reduce the number of group lookups
*/ */
int int
usergr_matches(group, user, pw) usergr_matches(group, user, pw)
@@ -539,24 +539,32 @@ usergr_matches(group, user, pw)
struct group *grp; struct group *grp;
gid_t pw_gid; gid_t pw_gid;
char **cur; char **cur;
int n;
/* make sure we have a valid usergroup, sudo style */ /* make sure we have a valid usergroup, sudo style */
if (*group++ != '%') if (*group++ != '%')
return(FALSE); return(FALSE);
/* look up user's primary gid in the passwd file */ /* look up user's primary gid in the passwd file */
if (pw == NULL && (pw = getpwnam(user)) == NULL) if (pw == NULL && (pw = sudo_getpwnam(user)) == NULL)
return(FALSE); return(FALSE);
pw_gid = pw->pw_gid; pw_gid = pw->pw_gid;
if ((grp = getgrnam(group)) == NULL) if ((grp = sudo_getgrnam(group)) == NULL)
return(FALSE); return(FALSE);
/* check against user's primary (passwd file) gid */ /* check against user's primary (passwd file) gid */
if (grp->gr_gid == pw_gid) if (grp->gr_gid == pw_gid)
return(TRUE); return(TRUE);
/* check the user's group vector */
n = user_ngroups;
while (n--)
if (grp->gr_gid == user_groups[n])
return(TRUE);
/* check to see if user is explicitly listed in the group */ /* check to see if user is explicitly listed in the group */
/* XXX - skip if group vector is set? */
for (cur = grp->gr_mem; *cur; cur++) { for (cur = grp->gr_mem; *cur; cur++) {
if (strcmp(*cur, user) == 0) if (strcmp(*cur, user) == 0)
return(TRUE); return(TRUE);

View File

@@ -22,9 +22,6 @@ typedef int (*schandler_t)
struct childinfo; struct childinfo;
struct listhead; struct listhead;
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 *));
static int check_execve __P((int, pid_t, u_int16_t, static int check_execve __P((int, pid_t, u_int16_t,

16
sudo.c
View File

@@ -107,9 +107,6 @@ 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_getpwuid __P((uid_t));
/* /*
* Globals * Globals
@@ -194,6 +191,7 @@ main(argc, argv, envp)
*/ */
initial_setup(); initial_setup();
sudo_setpwent(); sudo_setpwent();
sudo_setgrent();
/* Parse our arguments. */ /* Parse our arguments. */
sudo_mode = parse_args(Argc, Argv); sudo_mode = parse_args(Argc, Argv);
@@ -294,9 +292,9 @@ main(argc, argv, envp)
struct passwd *pw; struct passwd *pw;
if (*def_timestampowner == '#') if (*def_timestampowner == '#')
pw = getpwuid(atoi(def_timestampowner + 1)); pw = sudo_getpwuid(atoi(def_timestampowner + 1));
else else
pw = getpwnam(def_timestampowner); pw = sudo_getpwnam(def_timestampowner);
if (!pw) if (!pw)
log_error(0, "timestamp owner (%s): No such user", log_error(0, "timestamp owner (%s): No such user",
def_timestampowner); def_timestampowner);
@@ -397,7 +395,7 @@ main(argc, argv, envp)
/* Close the password and group files */ /* Close the password and group files */
sudo_endpwent(); sudo_endpwent();
endgrent(); sudo_endgrent();
/* Install the real environment. */ /* Install the real environment. */
environ = new_environ; environ = new_environ;
@@ -555,6 +553,12 @@ init_vars(sudo_mode)
/* It is now safe to use log_error() and set_perms() */ /* It is now safe to use log_error() and set_perms() */
if ((user_ngroups = getgroups(0, NULL)) > 0) {
user_groups = emalloc2(user_ngroups, sizeof(gid_t));
if (getgroups(user_ngroups, user_groups) < 0)
log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
}
if (def_fqdn) if (def_fqdn)
set_fqdn(); /* may call log_error() */ set_fqdn(); /* may call log_error() */

14
sudo.h
View File

@@ -40,7 +40,6 @@ struct sudo_user {
char *path; char *path;
char *shell; char *shell;
char *tty; char *tty;
char cwd[PATH_MAX];
char *host; char *host;
char *shost; char *shost;
char **runas; char **runas;
@@ -50,6 +49,9 @@ struct sudo_user {
char *cmnd_base; char *cmnd_base;
char *cmnd_safe; char *cmnd_safe;
char *class_name; char *class_name;
int ngroups;
gid_t *groups;
char cwd[PATH_MAX];
}; };
/* /*
@@ -123,6 +125,8 @@ struct sudo_user {
#define user_gid (sudo_user.pw->pw_gid) #define user_gid (sudo_user.pw->pw_gid)
#define user_dir (sudo_user.pw->pw_dir) #define user_dir (sudo_user.pw->pw_dir)
#define user_shell (sudo_user.shell) #define user_shell (sudo_user.shell)
#define user_ngroups (sudo_user.ngroups)
#define user_groups (sudo_user.groups)
#define user_tty (sudo_user.tty) #define user_tty (sudo_user.tty)
#define user_cwd (sudo_user.cwd) #define user_cwd (sudo_user.cwd)
#define user_runas (sudo_user.runas) #define user_runas (sudo_user.runas)
@@ -240,7 +244,15 @@ FILE *open_sudoers __P((const char *, int *));
void display_privs __P((struct passwd *)); void display_privs __P((struct passwd *));
void sudo_setpwent __P((void)); void sudo_setpwent __P((void));
void sudo_endpwent __P((void)); void sudo_endpwent __P((void));
void sudo_setgrent __P((void));
void sudo_endgrent __P((void));
void cleanup __P((void)); void cleanup __P((void));
struct passwd *sudo_getpwnam __P((const char *));
struct passwd *sudo_fakepwnam __P((const char *));
struct passwd *sudo_getpwuid __P((uid_t));
struct passwd *sudo_fakepwuid __P((uid_t));
struct group *sudo_getgrnam __P((const char *));
struct group *sudo_getgrgid __P((gid_t));
#ifdef HAVE_SYSTRACE #ifdef HAVE_SYSTRACE
void systrace_attach __P((pid_t)); void systrace_attach __P((pid_t));
#endif #endif

View File

@@ -147,10 +147,14 @@ main(argc, argv)
if (!dflag) if (!dflag)
usage(); usage();
user_name = "nobody"; user_name = "nobody";
user_cmnd = "true"; user_cmnd = user_base = "true";
} else { } else {
user_name = *argv++; user_name = *argv++;
user_cmnd = *argv; user_cmnd = *argv;
if ((p = strrchr(user_cmnd, '/')) != NULL)
user_base = p + 1;
else
user_base = user_cmnd;
NewArgc -= 2; NewArgc -= 2;
} }
@@ -275,6 +279,34 @@ set_perms(perm)
return; return;
} }
struct passwd *
sudo_getpwuid(uid)
uid_t uid;
{
return(getpwuid(uid));
}
struct passwd *
sudo_getpwnam(name)
const char *name;
{
return(getpwnam(name));
}
struct group *
sudo_getgrgid(gid)
gid_t gid;
{
return(getgrgid(gid));
}
struct group *
sudo_getgrnam(name)
const char *name;
{
return(getgrnam(name));
}
void void
cleanup() cleanup()
{ {

View File

@@ -60,6 +60,7 @@
#endif /* HAVE_UNISTD_H */ #endif /* HAVE_UNISTD_H */
#include <ctype.h> #include <ctype.h>
#include <pwd.h> #include <pwd.h>
#include <grp.h>
#include <time.h> #include <time.h>
#include <signal.h> #include <signal.h>
#include <errno.h> #include <errno.h>
@@ -524,6 +525,38 @@ user_is_exempt()
return(FALSE); return(FALSE);
} }
/* STUB */
struct passwd *
sudo_getpwuid(uid)
uid_t uid;
{
return(getpwuid(uid));
}
/* STUB */
struct passwd *
sudo_getpwnam(name)
const char *name;
{
return(getpwnam(name));
}
/* STUB */
struct group *
sudo_getgrgid(gid)
gid_t gid;
{
return(getgrgid(gid));
}
/* STUB */
struct group *
sudo_getgrnam(name)
const char *name;
{
return(getgrnam(name));
}
/* /*
* Assuming a parse error occurred, prompt the user for what they want * Assuming a parse error occurred, prompt the user for what they want
* to do now. Returns the first letter of their choice. * to do now. Returns the first letter of their choice.