version 1.1.1.3, 2012/10/09 09:29:52
|
version 1.1.1.4, 2013/07/22 10:46:12
|
Line 1
|
Line 1
|
/* |
/* |
* Copyright (c) 1996, 1998-2005, 2007-2012 | * Copyright (c) 1996, 1998-2005, 2007-2013 |
* Todd C. Miller <Todd.Miller@courtesan.com> |
* 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 |
Line 22
|
Line 22
|
#include <config.h> |
#include <config.h> |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
|
#include <sys/param.h> |
|
#include <stdio.h> |
#include <stdio.h> |
#ifdef STDC_HEADERS |
#ifdef STDC_HEADERS |
# include <stdlib.h> |
# include <stdlib.h> |
Line 48
|
Line 46
|
#ifdef HAVE_SETAUTHDB |
#ifdef HAVE_SETAUTHDB |
# include <usersec.h> |
# include <usersec.h> |
#endif /* HAVE_SETAUTHDB */ |
#endif /* HAVE_SETAUTHDB */ |
#ifdef HAVE_UTMPX_H |
|
# include <utmpx.h> |
|
#else |
|
# include <utmp.h> |
|
#endif /* HAVE_UTMPX_H */ |
|
#include <limits.h> |
|
#include <pwd.h> |
#include <pwd.h> |
#include <grp.h> |
#include <grp.h> |
|
|
#include "sudoers.h" |
#include "sudoers.h" |
#include "redblack.h" |
#include "redblack.h" |
|
#include "pwutil.h" |
|
|
/* |
/* |
* The passwd and group caches. |
* The passwd and group caches. |
Line 73 static int cmp_grgid(const void *, const void *);
|
Line 66 static int cmp_grgid(const void *, const void *);
|
|
|
#define cmp_grnam cmp_pwnam |
#define cmp_grnam cmp_pwnam |
|
|
#define ptr_to_item(p) ((struct cache_item *)((char *)p - offsetof(struct cache_item_##p, p))) |
|
|
|
/* |
/* |
* Generic cache element. |
|
*/ |
|
struct cache_item { |
|
unsigned int refcnt; |
|
/* key */ |
|
union { |
|
uid_t uid; |
|
gid_t gid; |
|
char *name; |
|
} k; |
|
/* datum */ |
|
union { |
|
struct passwd *pw; |
|
struct group *gr; |
|
struct group_list *grlist; |
|
} d; |
|
}; |
|
|
|
/* |
|
* Container structs to simpify size and offset calculations and guarantee |
|
* proper aligment of struct passwd, group and group_list. |
|
*/ |
|
struct cache_item_pw { |
|
struct cache_item cache; |
|
struct passwd pw; |
|
}; |
|
|
|
struct cache_item_gr { |
|
struct cache_item cache; |
|
struct group gr; |
|
}; |
|
|
|
struct cache_item_grlist { |
|
struct cache_item cache; |
|
struct group_list grlist; |
|
/* actually bigger */ |
|
}; |
|
|
|
/* |
|
* Compare by uid. |
* Compare by uid. |
*/ |
*/ |
static int |
static int |
Line 136 cmp_pwnam(const void *v1, const void *v2)
|
Line 88 cmp_pwnam(const void *v1, const void *v2)
|
return strcmp(ci1->k.name, ci2->k.name); |
return strcmp(ci1->k.name, ci2->k.name); |
} |
} |
|
|
#define FIELD_SIZE(src, name, size) \ |
|
do { \ |
|
if (src->name) { \ |
|
size = strlen(src->name) + 1; \ |
|
total += size; \ |
|
} \ |
|
} while (0) |
|
|
|
#define FIELD_COPY(src, dst, name, size) \ |
|
do { \ |
|
if (src->name) { \ |
|
memcpy(cp, src->name, size); \ |
|
dst->name = cp; \ |
|
cp += size; \ |
|
} \ |
|
} while (0) |
|
|
|
/* |
|
* Dynamically allocate space for a struct item plus the key and data |
|
* elements. If name is non-NULL it is used as the key, else the |
|
* uid is the key. Fills in datum from struct password. |
|
*/ |
|
static struct cache_item * |
|
make_pwitem(const struct passwd *pw, const char *name) |
|
{ |
|
char *cp; |
|
const char *pw_shell; |
|
size_t nsize, psize, csize, gsize, dsize, ssize, total; |
|
struct cache_item_pw *pwitem; |
|
struct passwd *newpw; |
|
debug_decl(make_pwitem, SUDO_DEBUG_NSS) |
|
|
|
/* If shell field is empty, expand to _PATH_BSHELL. */ |
|
pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0') |
|
? _PATH_BSHELL : pw->pw_shell; |
|
|
|
/* Allocate in one big chunk for easy freeing. */ |
|
nsize = psize = csize = gsize = dsize = ssize = 0; |
|
total = sizeof(*pwitem); |
|
FIELD_SIZE(pw, pw_name, nsize); |
|
FIELD_SIZE(pw, pw_passwd, psize); |
|
#ifdef HAVE_LOGIN_CAP_H |
|
FIELD_SIZE(pw, pw_class, csize); |
|
#endif |
|
FIELD_SIZE(pw, pw_gecos, gsize); |
|
FIELD_SIZE(pw, pw_dir, dsize); |
|
/* Treat shell specially since we expand "" -> _PATH_BSHELL */ |
|
ssize = strlen(pw_shell) + 1; |
|
total += ssize; |
|
if (name != NULL) |
|
total += strlen(name) + 1; |
|
|
|
/* Allocate space for struct item, struct passwd and the strings. */ |
|
pwitem = ecalloc(1, total); |
|
newpw = &pwitem->pw; |
|
|
|
/* |
|
* Copy in passwd contents and make strings relative to space |
|
* at the end of the struct. |
|
*/ |
|
memcpy(newpw, pw, sizeof(*pw)); |
|
cp = (char *)(pwitem + 1); |
|
FIELD_COPY(pw, newpw, pw_name, nsize); |
|
FIELD_COPY(pw, newpw, pw_passwd, psize); |
|
#ifdef HAVE_LOGIN_CAP_H |
|
FIELD_COPY(pw, newpw, pw_class, csize); |
|
#endif |
|
FIELD_COPY(pw, newpw, pw_gecos, gsize); |
|
FIELD_COPY(pw, newpw, pw_dir, dsize); |
|
/* Treat shell specially since we expand "" -> _PATH_BSHELL */ |
|
memcpy(cp, pw_shell, ssize); |
|
newpw->pw_shell = cp; |
|
cp += ssize; |
|
|
|
/* Set key and datum. */ |
|
if (name != NULL) { |
|
memcpy(cp, name, strlen(name) + 1); |
|
pwitem->cache.k.name = cp; |
|
} else { |
|
pwitem->cache.k.uid = pw->pw_uid; |
|
} |
|
pwitem->cache.d.pw = newpw; |
|
pwitem->cache.refcnt = 1; |
|
|
|
debug_return_ptr(&pwitem->cache); |
|
} |
|
|
|
void |
void |
sudo_pw_addref(struct passwd *pw) |
sudo_pw_addref(struct passwd *pw) |
{ |
{ |
Line 272 sudo_getpwuid(uid_t uid)
|
Line 137 sudo_getpwuid(uid_t uid)
|
#ifdef HAVE_SETAUTHDB |
#ifdef HAVE_SETAUTHDB |
aix_setauthdb(IDtouser(uid)); |
aix_setauthdb(IDtouser(uid)); |
#endif |
#endif |
if ((key.d.pw = getpwuid(uid)) != NULL) { | item = sudo_make_pwitem(uid, NULL); |
item = make_pwitem(key.d.pw, NULL); | if (item == NULL) { |
if (rbinsert(pwcache_byuid, item) != NULL) | |
errorx(1, _("unable to cache uid %u (%s), already exists"), | |
(unsigned int) uid, item->d.pw->pw_name); | |
} else { | |
item = ecalloc(1, sizeof(*item)); |
item = ecalloc(1, sizeof(*item)); |
item->refcnt = 1; |
item->refcnt = 1; |
item->k.uid = uid; |
item->k.uid = uid; |
/* item->d.pw = NULL; */ |
/* item->d.pw = NULL; */ |
if (rbinsert(pwcache_byuid, item) != NULL) |
|
errorx(1, _("unable to cache uid %u, already exists"), |
|
(unsigned int) uid); |
|
} |
} |
|
if (rbinsert(pwcache_byuid, item) != NULL) |
|
fatalx(_("unable to cache uid %u, already exists"), |
|
(unsigned int) uid); |
#ifdef HAVE_SETAUTHDB |
#ifdef HAVE_SETAUTHDB |
aix_restoreauthdb(); |
aix_restoreauthdb(); |
#endif |
#endif |
Line 316 sudo_getpwnam(const char *name)
|
Line 177 sudo_getpwnam(const char *name)
|
#ifdef HAVE_SETAUTHDB |
#ifdef HAVE_SETAUTHDB |
aix_setauthdb((char *) name); |
aix_setauthdb((char *) name); |
#endif |
#endif |
if ((key.d.pw = getpwnam(name)) != NULL) { | item = sudo_make_pwitem((uid_t)-1, name); |
item = make_pwitem(key.d.pw, name); | if (item == NULL) { |
if (rbinsert(pwcache_byname, item) != NULL) | |
errorx(1, _("unable to cache user %s, already exists"), name); | |
} else { | |
len = strlen(name) + 1; |
len = strlen(name) + 1; |
item = ecalloc(1, sizeof(*item) + len); |
item = ecalloc(1, sizeof(*item) + len); |
item->refcnt = 1; |
item->refcnt = 1; |
item->k.name = (char *) item + sizeof(*item); |
item->k.name = (char *) item + sizeof(*item); |
memcpy(item->k.name, name, len); |
memcpy(item->k.name, name, len); |
/* item->d.pw = NULL; */ |
/* item->d.pw = NULL; */ |
if (rbinsert(pwcache_byname, item) != NULL) |
|
errorx(1, _("unable to cache user %s, already exists"), name); |
|
} |
} |
|
if (rbinsert(pwcache_byname, item) != NULL) |
|
fatalx(_("unable to cache user %s, already exists"), name); |
#ifdef HAVE_SETAUTHDB |
#ifdef HAVE_SETAUTHDB |
aix_restoreauthdb(); |
aix_restoreauthdb(); |
#endif |
#endif |
Line 339 done:
|
Line 197 done:
|
} |
} |
|
|
/* |
/* |
* Take a user, uid and gid and return a faked up passwd struct. | * Take a user, uid, gid, home and shell and return a faked up passwd struct. |
| * If home or shell are NULL default values will be used. |
*/ |
*/ |
struct passwd * |
struct passwd * |
sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid) | sudo_mkpwent(const char *user, uid_t uid, gid_t gid, const char *home, |
| const char *shell) |
{ |
{ |
struct cache_item_pw *pwitem; |
struct cache_item_pw *pwitem; |
struct passwd *pw; |
struct passwd *pw; |
struct rbnode *node; |
struct rbnode *node; |
size_t len, namelen; | size_t len, name_len, home_len, shell_len; |
int i; |
int i; |
debug_decl(sudo_fakepwnam, SUDO_DEBUG_NSS) | debug_decl(sudo_mkpwent, SUDO_DEBUG_NSS) |
|
|
namelen = strlen(user); | /* Optional arguments. */ |
len = sizeof(*pwitem) + namelen + 1 /* pw_name */ + | if (home == NULL) |
| home = "/"; |
| if (shell == NULL) |
| shell = _PATH_BSHELL; |
| |
| name_len = strlen(user); |
| home_len = strlen(home); |
| shell_len = strlen(shell); |
| len = sizeof(*pwitem) + name_len + 1 /* pw_name */ + |
sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ + |
sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ + |
sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL); | home_len + 1 /* pw_dir */ + shell_len + 1 /* pw_shell */; |
|
|
for (i = 0; i < 2; i++) { |
for (i = 0; i < 2; i++) { |
pwitem = ecalloc(1, len); |
pwitem = ecalloc(1, len); |
Line 362 sudo_fakepwnamid(const char *user, uid_t uid, gid_t gi
|
Line 230 sudo_fakepwnamid(const char *user, uid_t uid, gid_t gi
|
pw->pw_uid = uid; |
pw->pw_uid = uid; |
pw->pw_gid = gid; |
pw->pw_gid = gid; |
pw->pw_name = (char *)(pwitem + 1); |
pw->pw_name = (char *)(pwitem + 1); |
memcpy(pw->pw_name, user, namelen + 1); | memcpy(pw->pw_name, user, name_len + 1); |
pw->pw_passwd = pw->pw_name + namelen + 1; | pw->pw_passwd = pw->pw_name + name_len + 1; |
memcpy(pw->pw_passwd, "*", 2); |
memcpy(pw->pw_passwd, "*", 2); |
pw->pw_gecos = pw->pw_passwd + 2; |
pw->pw_gecos = pw->pw_passwd + 2; |
pw->pw_gecos[0] = '\0'; |
pw->pw_gecos[0] = '\0'; |
pw->pw_dir = pw->pw_gecos + 1; |
pw->pw_dir = pw->pw_gecos + 1; |
memcpy(pw->pw_dir, "/", 2); | memcpy(pw->pw_dir, home, home_len + 1); |
pw->pw_shell = pw->pw_dir + 2; | pw->pw_shell = pw->pw_dir + home_len + 1; |
memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL)); | memcpy(pw->pw_shell, shell, shell_len + 1); |
|
|
pwitem->cache.refcnt = 1; |
pwitem->cache.refcnt = 1; |
pwitem->cache.d.pw = pw; |
pwitem->cache.d.pw = pw; |
if (i == 0) { |
if (i == 0) { |
/* Store by uid, overwriting cached version. */ | /* Store by uid if it doesn't already exist. */ |
pwitem->cache.k.uid = pw->pw_uid; |
pwitem->cache.k.uid = pw->pw_uid; |
if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) { |
if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) { |
sudo_pw_delref_item(node->data); | /* Already exists, free the item we created. */ |
node->data = &pwitem->cache; | efree(pwitem); |
| pwitem = (struct cache_item_pw *) node->data; |
} |
} |
} else { |
} else { |
/* Store by name, overwriting cached version. */ | /* Store by name if it doesn't already exist. */ |
pwitem->cache.k.name = pw->pw_name; |
pwitem->cache.k.name = pw->pw_name; |
if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) { |
if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) { |
sudo_pw_delref_item(node->data); | /* Already exists, free the item we created. */ |
node->data = &pwitem->cache; | efree(pwitem); |
| pwitem = (struct cache_item_pw *) node->data; |
} |
} |
} |
} |
} |
} |
pwitem->cache.refcnt++; |
pwitem->cache.refcnt++; |
debug_return_ptr(pw); | debug_return_ptr(&pwitem->pw); |
} |
} |
|
|
/* |
/* |
Line 403 sudo_fakepwnam(const char *user, gid_t gid)
|
Line 273 sudo_fakepwnam(const char *user, gid_t gid)
|
uid_t uid; |
uid_t uid; |
|
|
uid = (uid_t) atoi(user + 1); |
uid = (uid_t) atoi(user + 1); |
return sudo_fakepwnamid(user, uid, gid); | return sudo_mkpwent(user, uid, gid, NULL, NULL); |
} |
} |
|
|
void |
void |
Line 459 cmp_grgid(const void *v1, const void *v2)
|
Line 329 cmp_grgid(const void *v1, const void *v2)
|
return ci1->k.gid - ci2->k.gid; |
return ci1->k.gid - ci2->k.gid; |
} |
} |
|
|
/* |
|
* Dynamically allocate space for a struct item plus the key and data |
|
* elements. If name is non-NULL it is used as the key, else the |
|
* gid is the key. Fills in datum from struct group. |
|
*/ |
|
static struct cache_item * |
|
make_gritem(const struct group *gr, const char *name) |
|
{ |
|
char *cp; |
|
size_t nsize, psize, nmem, total, len; |
|
struct cache_item_gr *gritem; |
|
struct group *newgr; |
|
debug_decl(make_gritem, SUDO_DEBUG_NSS) |
|
|
|
/* Allocate in one big chunk for easy freeing. */ |
|
nsize = psize = nmem = 0; |
|
total = sizeof(*gritem); |
|
FIELD_SIZE(gr, gr_name, nsize); |
|
FIELD_SIZE(gr, gr_passwd, psize); |
|
if (gr->gr_mem) { |
|
for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++) |
|
total += strlen(gr->gr_mem[nmem]) + 1; |
|
nmem++; |
|
total += sizeof(char *) * nmem; |
|
} |
|
if (name != NULL) |
|
total += strlen(name) + 1; |
|
|
|
gritem = ecalloc(1, total); |
|
|
|
/* |
|
* Copy in group contents and make strings relative to space |
|
* at the end of the buffer. Note that gr_mem must come |
|
* immediately after struct group to guarantee proper alignment. |
|
*/ |
|
newgr = &gritem->gr; |
|
memcpy(newgr, gr, sizeof(*gr)); |
|
cp = (char *)(gritem + 1); |
|
if (gr->gr_mem) { |
|
newgr->gr_mem = (char **)cp; |
|
cp += sizeof(char *) * nmem; |
|
for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++) { |
|
len = strlen(gr->gr_mem[nmem]) + 1; |
|
memcpy(cp, gr->gr_mem[nmem], len); |
|
newgr->gr_mem[nmem] = cp; |
|
cp += len; |
|
} |
|
newgr->gr_mem[nmem] = NULL; |
|
} |
|
FIELD_COPY(gr, newgr, gr_passwd, psize); |
|
FIELD_COPY(gr, newgr, gr_name, nsize); |
|
|
|
/* Set key and datum. */ |
|
if (name != NULL) { |
|
memcpy(cp, name, strlen(name) + 1); |
|
gritem->cache.k.name = cp; |
|
} else { |
|
gritem->cache.k.gid = gr->gr_gid; |
|
} |
|
gritem->cache.d.gr = newgr; |
|
gritem->cache.refcnt = 1; |
|
|
|
debug_return_ptr(&gritem->cache); |
|
} |
|
|
|
#ifdef HAVE_UTMPX_H |
|
# define GROUPNAME_LEN (sizeof((struct utmpx *)0)->ut_user + 1) |
|
#else |
|
# ifdef HAVE_STRUCT_UTMP_UT_USER |
|
# define GROUPNAME_LEN (sizeof((struct utmp *)0)->ut_user + 1) |
|
# else |
|
# define GROUPNAME_LEN (sizeof((struct utmp *)0)->ut_name + 1) |
|
# endif |
|
#endif /* HAVE_UTMPX_H */ |
|
|
|
/* |
|
* Dynamically allocate space for a struct item plus the key and data |
|
* elements. Fills in datum from the groups and gids arrays. |
|
*/ |
|
static struct cache_item * |
|
make_grlist_item(const char *user, GETGROUPS_T *gids, int ngids) |
|
{ |
|
char *cp; |
|
size_t i, nsize, ngroups, total, len; |
|
struct cache_item_grlist *grlitem; |
|
struct group_list *grlist; |
|
struct group *grp; |
|
debug_decl(make_grlist_item, SUDO_DEBUG_NSS) |
|
|
|
#ifdef HAVE_SETAUTHDB |
|
aix_setauthdb((char *) user); |
|
#endif |
|
|
|
/* Allocate in one big chunk for easy freeing. */ |
|
nsize = strlen(user) + 1; |
|
total = sizeof(*grlitem) + nsize; |
|
total += sizeof(char *) * ngids; |
|
total += sizeof(gid_t *) * ngids; |
|
total += GROUPNAME_LEN * ngids; |
|
|
|
again: |
|
grlitem = ecalloc(1, total); |
|
|
|
/* |
|
* Copy in group list and make pointers relative to space |
|
* at the end of the buffer. Note that the groups array must come |
|
* immediately after struct group to guarantee proper alignment. |
|
*/ |
|
grlist = &grlitem->grlist; |
|
cp = (char *)(grlitem + 1); |
|
grlist->groups = (char **)cp; |
|
cp += sizeof(char *) * ngids; |
|
grlist->gids = (gid_t *)cp; |
|
cp += sizeof(gid_t) * ngids; |
|
|
|
/* Set key and datum. */ |
|
memcpy(cp, user, nsize); |
|
grlitem->cache.k.name = cp; |
|
grlitem->cache.d.grlist = grlist; |
|
grlitem->cache.refcnt = 1; |
|
cp += nsize; |
|
|
|
/* |
|
* Store group IDs. |
|
*/ |
|
for (i = 0; i < ngids; i++) |
|
grlist->gids[i] = gids[i]; |
|
grlist->ngids = ngids; |
|
|
|
/* |
|
* Resolve and store group names by ID. |
|
*/ |
|
ngroups = 0; |
|
for (i = 0; i < ngids; i++) { |
|
if ((grp = sudo_getgrgid(gids[i])) != NULL) { |
|
len = strlen(grp->gr_name) + 1; |
|
if (cp - (char *)grlitem + len > total) { |
|
total += len + GROUPNAME_LEN; |
|
efree(grlitem); |
|
sudo_gr_delref(grp); |
|
goto again; |
|
} |
|
memcpy(cp, grp->gr_name, len); |
|
grlist->groups[ngroups++] = cp; |
|
cp += len; |
|
sudo_gr_delref(grp); |
|
} |
|
} |
|
grlist->ngroups = ngroups; |
|
|
|
#ifdef HAVE_SETAUTHDB |
|
aix_restoreauthdb(); |
|
#endif |
|
|
|
debug_return_ptr(&grlitem->cache); |
|
} |
|
|
|
void |
void |
sudo_gr_addref(struct group *gr) |
sudo_gr_addref(struct group *gr) |
{ |
{ |
Line 662 sudo_getgrgid(gid_t gid)
|
Line 375 sudo_getgrgid(gid_t gid)
|
/* |
/* |
* Cache group db entry if it exists or a negative response if not. |
* Cache group db entry if it exists or a negative response if not. |
*/ |
*/ |
if ((key.d.gr = getgrgid(gid)) != NULL) { | item = sudo_make_gritem(gid, NULL); |
item = make_gritem(key.d.gr, NULL); | if (item == NULL) { |
if (rbinsert(grcache_bygid, item) != NULL) | |
errorx(1, _("unable to cache gid %u (%s), already exists"), | |
(unsigned int) gid, key.d.gr->gr_name); | |
} else { | |
item = ecalloc(1, sizeof(*item)); |
item = ecalloc(1, sizeof(*item)); |
item->refcnt = 1; |
item->refcnt = 1; |
item->k.gid = gid; |
item->k.gid = gid; |
/* item->d.gr = NULL; */ |
/* item->d.gr = NULL; */ |
if (rbinsert(grcache_bygid, item) != NULL) |
|
errorx(1, _("unable to cache gid %u, already exists"), |
|
(unsigned int) gid); |
|
} |
} |
|
if (rbinsert(grcache_bygid, item) != NULL) |
|
fatalx(_("unable to cache gid %u, already exists"), |
|
(unsigned int) gid); |
done: |
done: |
item->refcnt++; |
item->refcnt++; |
debug_return_ptr(item->d.gr); |
debug_return_ptr(item->d.gr); |
Line 700 sudo_getgrnam(const char *name)
|
Line 409 sudo_getgrnam(const char *name)
|
/* |
/* |
* Cache group db entry if it exists or a negative response if not. |
* Cache group db entry if it exists or a negative response if not. |
*/ |
*/ |
if ((key.d.gr = getgrnam(name)) != NULL) { | item = sudo_make_gritem((gid_t)-1, name); |
item = make_gritem(key.d.gr, name); | if (item == NULL) { |
if (rbinsert(grcache_byname, item) != NULL) | |
errorx(1, _("unable to cache group %s, already exists"), name); | |
} else { | |
len = strlen(name) + 1; |
len = strlen(name) + 1; |
item = ecalloc(1, sizeof(*item) + len); |
item = ecalloc(1, sizeof(*item) + len); |
item->refcnt = 1; |
item->refcnt = 1; |
item->k.name = (char *) item + sizeof(*item); |
item->k.name = (char *) item + sizeof(*item); |
memcpy(item->k.name, name, len); |
memcpy(item->k.name, name, len); |
/* item->d.gr = NULL; */ |
/* item->d.gr = NULL; */ |
if (rbinsert(grcache_byname, item) != NULL) |
|
errorx(1, _("unable to cache group %s, already exists"), name); |
|
} |
} |
|
if (rbinsert(grcache_byname, item) != NULL) |
|
fatalx(_("unable to cache group %s, already exists"), name); |
done: |
done: |
item->refcnt++; |
item->refcnt++; |
debug_return_ptr(item->d.gr); |
debug_return_ptr(item->d.gr); |
Line 728 sudo_fakegrnam(const char *group)
|
Line 434 sudo_fakegrnam(const char *group)
|
struct cache_item_gr *gritem; |
struct cache_item_gr *gritem; |
struct group *gr; |
struct group *gr; |
struct rbnode *node; |
struct rbnode *node; |
size_t len, namelen; | size_t len, name_len; |
int i; |
int i; |
debug_decl(sudo_fakegrnam, SUDO_DEBUG_NSS) |
debug_decl(sudo_fakegrnam, SUDO_DEBUG_NSS) |
|
|
namelen = strlen(group); | name_len = strlen(group); |
len = sizeof(*gritem) + namelen + 1; | len = sizeof(*gritem) + name_len + 1; |
|
|
for (i = 0; i < 2; i++) { |
for (i = 0; i < 2; i++) { |
gritem = ecalloc(1, len); |
gritem = ecalloc(1, len); |
gr = &gritem->gr; |
gr = &gritem->gr; |
gr->gr_gid = (gid_t) atoi(group + 1); |
gr->gr_gid = (gid_t) atoi(group + 1); |
gr->gr_name = (char *)(gritem + 1); |
gr->gr_name = (char *)(gritem + 1); |
memcpy(gr->gr_name, group, namelen + 1); | memcpy(gr->gr_name, group, name_len + 1); |
|
|
gritem->cache.refcnt = 1; |
gritem->cache.refcnt = 1; |
gritem->cache.d.gr = gr; |
gritem->cache.d.gr = gr; |
if (i == 0) { |
if (i == 0) { |
/* Store by gid, overwriting cached version. */ | /* Store by gid if it doesn't already exist. */ |
gritem->cache.k.gid = gr->gr_gid; |
gritem->cache.k.gid = gr->gr_gid; |
if ((node = rbinsert(grcache_bygid, &gritem->cache)) != NULL) { |
if ((node = rbinsert(grcache_bygid, &gritem->cache)) != NULL) { |
sudo_gr_delref_item(node->data); | /* Already exists, free the item we created. */ |
node->data = &gritem->cache; | efree(gritem); |
| gritem = (struct cache_item_gr *) node->data; |
} |
} |
} else { |
} else { |
/* Store by name, overwriting cached version. */ |
/* Store by name, overwriting cached version. */ |
gritem->cache.k.name = gr->gr_name; |
gritem->cache.k.name = gr->gr_name; |
if ((node = rbinsert(grcache_byname, &gritem->cache)) != NULL) { |
if ((node = rbinsert(grcache_byname, &gritem->cache)) != NULL) { |
sudo_gr_delref_item(node->data); | /* Already exists, free the item we created. */ |
node->data = &gritem->cache; | efree(gritem); |
| gritem = (struct cache_item_gr *) node->data; |
} |
} |
} |
} |
} |
} |
gritem->cache.refcnt++; |
gritem->cache.refcnt++; |
debug_return_ptr(gr); | debug_return_ptr(&gritem->gr); |
} |
} |
|
|
void |
void |
Line 846 sudo_get_grlist(struct passwd *pw)
|
Line 554 sudo_get_grlist(struct passwd *pw)
|
struct cache_item key, *item; |
struct cache_item key, *item; |
struct rbnode *node; |
struct rbnode *node; |
size_t len; |
size_t len; |
GETGROUPS_T *gids; |
|
int ngids; |
|
debug_decl(sudo_get_grlist, SUDO_DEBUG_NSS) |
debug_decl(sudo_get_grlist, SUDO_DEBUG_NSS) |
|
|
key.k.name = pw->pw_name; |
key.k.name = pw->pw_name; |
Line 857 sudo_get_grlist(struct passwd *pw)
|
Line 563 sudo_get_grlist(struct passwd *pw)
|
} |
} |
/* |
/* |
* Cache group db entry if it exists or a negative response if not. |
* Cache group db entry if it exists or a negative response if not. |
* Use gids list from front-end if possible, otherwise getgrouplist(). |
|
*/ |
*/ |
if (pw == sudo_user.pw && sudo_user.gids != NULL) { | item = sudo_make_grlist_item(pw, NULL, NULL); |
gids = user_gids; | if (item == NULL) { |
ngids = user_ngids; | |
user_gids = NULL; | |
user_ngids = 0; | |
} else { | |
#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) | |
ngids = (int)sysconf(_SC_NGROUPS_MAX) * 2; | |
if (ngids < 0) | |
#endif | |
ngids = NGROUPS_MAX * 2; | |
gids = emalloc2(ngids, sizeof(GETGROUPS_T)); | |
if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) { | |
efree(gids); | |
gids = emalloc2(ngids, sizeof(GETGROUPS_T)); | |
if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) { | |
efree(gids); | |
debug_return_ptr(NULL); | |
} | |
} | |
} | |
if (ngids > 0) { | |
if ((item = make_grlist_item(pw->pw_name, gids, ngids)) == NULL) | |
errorx(1, "unable to parse group list for %s", pw->pw_name); | |
efree(gids); | |
if (rbinsert(grlist_cache, item) != NULL) | |
errorx(1, "unable to cache group list for %s, already exists", | |
pw->pw_name); | |
} else { | |
/* Should not happen. */ |
/* Should not happen. */ |
len = strlen(pw->pw_name) + 1; |
len = strlen(pw->pw_name) + 1; |
item = ecalloc(1, sizeof(*item) + len); |
item = ecalloc(1, sizeof(*item) + len); |
Line 895 sudo_get_grlist(struct passwd *pw)
|
Line 573 sudo_get_grlist(struct passwd *pw)
|
item->k.name = (char *) item + sizeof(*item); |
item->k.name = (char *) item + sizeof(*item); |
memcpy(item->k.name, pw->pw_name, len); |
memcpy(item->k.name, pw->pw_name, len); |
/* item->d.grlist = NULL; */ |
/* item->d.grlist = NULL; */ |
if (rbinsert(grlist_cache, item) != NULL) |
|
errorx(1, "unable to cache group list for %s, already exists", |
|
pw->pw_name); |
|
} |
} |
|
if (rbinsert(grlist_cache, item) != NULL) |
|
fatalx(_("unable to cache group list for %s, already exists"), |
|
pw->pw_name); |
done: |
done: |
item->refcnt++; |
item->refcnt++; |
debug_return_ptr(item->d.grlist); |
debug_return_ptr(item->d.grlist); |
|
} |
|
|
|
void |
|
sudo_set_grlist(struct passwd *pw, char * const *groups, char * const *gids) |
|
{ |
|
struct cache_item key, *item; |
|
struct rbnode *node; |
|
debug_decl(sudo_set_grlist, SUDO_DEBUG_NSS) |
|
|
|
/* |
|
* Cache group db entry if it doesn't already exist |
|
*/ |
|
key.k.name = pw->pw_name; |
|
if ((node = rbfind(grlist_cache, &key)) == NULL) { |
|
if ((item = sudo_make_grlist_item(pw, groups, gids)) == NULL) |
|
fatalx(_("unable to parse groups for %s"), pw->pw_name); |
|
if (rbinsert(grlist_cache, item) != NULL) |
|
fatalx(_("unable to cache group list for %s, already exists"), |
|
pw->pw_name); |
|
} |
|
debug_return; |
} |
} |
|
|
bool |
bool |