Fix an alignment problem on NetBSD systems with a 64-bit time_t and
strict alignment. Based on a patch from Martin Husemann.
This commit is contained in:
@@ -73,8 +73,11 @@ 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) - sizeof(struct cache_item)))
|
#define ptr_to_item(p) ((struct cache_item *)((char *)p - offsetof(struct cache_item_##p, p)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic cache element.
|
||||||
|
*/
|
||||||
struct cache_item {
|
struct cache_item {
|
||||||
unsigned int refcnt;
|
unsigned int refcnt;
|
||||||
/* key */
|
/* key */
|
||||||
@@ -91,6 +94,26 @@ struct cache_item {
|
|||||||
} d;
|
} 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.
|
||||||
*/
|
*/
|
||||||
@@ -134,9 +157,6 @@ do { \
|
|||||||
* Dynamically allocate space for a struct item plus the key and data
|
* 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
|
* elements. If name is non-NULL it is used as the key, else the
|
||||||
* uid is the key. Fills in datum from struct password.
|
* uid is the key. Fills in datum from struct password.
|
||||||
*
|
|
||||||
* We would like to fill in the encrypted password too but the
|
|
||||||
* call to the shadow function could overwrite the pw buffer (NIS).
|
|
||||||
*/
|
*/
|
||||||
static struct cache_item *
|
static struct cache_item *
|
||||||
make_pwitem(const struct passwd *pw, const char *name)
|
make_pwitem(const struct passwd *pw, const char *name)
|
||||||
@@ -144,7 +164,7 @@ make_pwitem(const struct passwd *pw, const char *name)
|
|||||||
char *cp;
|
char *cp;
|
||||||
const char *pw_shell;
|
const char *pw_shell;
|
||||||
size_t nsize, psize, csize, gsize, dsize, ssize, total;
|
size_t nsize, psize, csize, gsize, dsize, ssize, total;
|
||||||
struct cache_item *item;
|
struct cache_item_pw *pwitem;
|
||||||
struct passwd *newpw;
|
struct passwd *newpw;
|
||||||
debug_decl(make_pwitem, SUDO_DEBUG_NSS)
|
debug_decl(make_pwitem, SUDO_DEBUG_NSS)
|
||||||
|
|
||||||
@@ -154,7 +174,7 @@ make_pwitem(const struct passwd *pw, const char *name)
|
|||||||
|
|
||||||
/* Allocate in one big chunk for easy freeing. */
|
/* Allocate in one big chunk for easy freeing. */
|
||||||
nsize = psize = csize = gsize = dsize = ssize = 0;
|
nsize = psize = csize = gsize = dsize = ssize = 0;
|
||||||
total = sizeof(struct cache_item) + sizeof(struct passwd);
|
total = sizeof(*pwitem);
|
||||||
FIELD_SIZE(pw, pw_name, nsize);
|
FIELD_SIZE(pw, pw_name, nsize);
|
||||||
FIELD_SIZE(pw, pw_passwd, psize);
|
FIELD_SIZE(pw, pw_passwd, psize);
|
||||||
#ifdef HAVE_LOGIN_CAP_H
|
#ifdef HAVE_LOGIN_CAP_H
|
||||||
@@ -169,16 +189,15 @@ make_pwitem(const struct passwd *pw, const char *name)
|
|||||||
total += strlen(name) + 1;
|
total += strlen(name) + 1;
|
||||||
|
|
||||||
/* Allocate space for struct item, struct passwd and the strings. */
|
/* Allocate space for struct item, struct passwd and the strings. */
|
||||||
item = ecalloc(1, total);
|
pwitem = ecalloc(1, total);
|
||||||
cp = (char *) item + sizeof(struct cache_item);
|
newpw = &pwitem->pw;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy in passwd contents and make strings relative to space
|
* Copy in passwd contents and make strings relative to space
|
||||||
* at the end of the buffer.
|
* at the end of the struct.
|
||||||
*/
|
*/
|
||||||
newpw = (struct passwd *) cp;
|
memcpy(newpw, pw, sizeof(*pw));
|
||||||
memcpy(newpw, pw, sizeof(struct passwd));
|
cp = (char *)(pwitem + 1);
|
||||||
cp += sizeof(struct passwd);
|
|
||||||
FIELD_COPY(pw, newpw, pw_name, nsize);
|
FIELD_COPY(pw, newpw, pw_name, nsize);
|
||||||
FIELD_COPY(pw, newpw, pw_passwd, psize);
|
FIELD_COPY(pw, newpw, pw_passwd, psize);
|
||||||
#ifdef HAVE_LOGIN_CAP_H
|
#ifdef HAVE_LOGIN_CAP_H
|
||||||
@@ -194,14 +213,14 @@ make_pwitem(const struct passwd *pw, const char *name)
|
|||||||
/* Set key and datum. */
|
/* Set key and datum. */
|
||||||
if (name != NULL) {
|
if (name != NULL) {
|
||||||
memcpy(cp, name, strlen(name) + 1);
|
memcpy(cp, name, strlen(name) + 1);
|
||||||
item->k.name = cp;
|
pwitem->cache.k.name = cp;
|
||||||
} else {
|
} else {
|
||||||
item->k.uid = pw->pw_uid;
|
pwitem->cache.k.uid = pw->pw_uid;
|
||||||
}
|
}
|
||||||
item->d.pw = newpw;
|
pwitem->cache.d.pw = newpw;
|
||||||
item->refcnt = 1;
|
pwitem->cache.refcnt = 1;
|
||||||
|
|
||||||
debug_return_ptr(item);
|
debug_return_ptr(&pwitem->cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -234,7 +253,6 @@ pw_delref(struct passwd *pw)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a password entry by uid and allocate space for it.
|
* Get a password entry by uid and allocate space for it.
|
||||||
* Fills in pw_passwd from shadow file if necessary.
|
|
||||||
*/
|
*/
|
||||||
struct passwd *
|
struct passwd *
|
||||||
sudo_getpwuid(uid_t uid)
|
sudo_getpwuid(uid_t uid)
|
||||||
@@ -278,7 +296,6 @@ done:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a password entry by name and allocate space for it.
|
* Get a password entry by name and allocate space for it.
|
||||||
* Fills in pw_passwd from shadow file if necessary.
|
|
||||||
*/
|
*/
|
||||||
struct passwd *
|
struct passwd *
|
||||||
sudo_getpwnam(const char *name)
|
sudo_getpwnam(const char *name)
|
||||||
@@ -327,7 +344,7 @@ done:
|
|||||||
struct passwd *
|
struct passwd *
|
||||||
sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid)
|
sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid)
|
||||||
{
|
{
|
||||||
struct cache_item *item;
|
struct cache_item_pw *pwitem;
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
struct rbnode *node;
|
struct rbnode *node;
|
||||||
size_t len, namelen;
|
size_t len, namelen;
|
||||||
@@ -335,16 +352,16 @@ sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid)
|
|||||||
debug_decl(sudo_fakepwnam, SUDO_DEBUG_NSS)
|
debug_decl(sudo_fakepwnam, SUDO_DEBUG_NSS)
|
||||||
|
|
||||||
namelen = strlen(user);
|
namelen = strlen(user);
|
||||||
len = sizeof(*item) + sizeof(*pw) + namelen + 1 /* pw_name */ +
|
len = sizeof(*pwitem) + namelen + 1 /* pw_name */ +
|
||||||
sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +
|
sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +
|
||||||
sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL);
|
sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL);
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
item = ecalloc(1, len);
|
pwitem = ecalloc(1, len);
|
||||||
pw = (struct passwd *) ((char *)item + sizeof(*item));
|
pw = &pwitem->pw;
|
||||||
pw->pw_uid = uid;
|
pw->pw_uid = uid;
|
||||||
pw->pw_gid = gid;
|
pw->pw_gid = gid;
|
||||||
pw->pw_name = (char *)pw + sizeof(struct passwd);
|
pw->pw_name = (char *)(pwitem + 1);
|
||||||
memcpy(pw->pw_name, user, namelen + 1);
|
memcpy(pw->pw_name, user, namelen + 1);
|
||||||
pw->pw_passwd = pw->pw_name + namelen + 1;
|
pw->pw_passwd = pw->pw_name + namelen + 1;
|
||||||
memcpy(pw->pw_passwd, "*", 2);
|
memcpy(pw->pw_passwd, "*", 2);
|
||||||
@@ -355,25 +372,25 @@ sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid)
|
|||||||
pw->pw_shell = pw->pw_dir + 2;
|
pw->pw_shell = pw->pw_dir + 2;
|
||||||
memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL));
|
memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL));
|
||||||
|
|
||||||
item->refcnt = 1;
|
pwitem->cache.refcnt = 1;
|
||||||
item->d.pw = pw;
|
pwitem->cache.d.pw = pw;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
/* Store by uid, overwriting cached version. */
|
/* Store by uid, overwriting cached version. */
|
||||||
item->k.uid = pw->pw_uid;
|
pwitem->cache.k.uid = pw->pw_uid;
|
||||||
if ((node = rbinsert(pwcache_byuid, item)) != NULL) {
|
if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) {
|
||||||
pw_delref_item(node->data);
|
pw_delref_item(node->data);
|
||||||
node->data = item;
|
node->data = &pwitem->cache;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Store by name, overwriting cached version. */
|
/* Store by name, overwriting cached version. */
|
||||||
item->k.name = pw->pw_name;
|
pwitem->cache.k.name = pw->pw_name;
|
||||||
if ((node = rbinsert(pwcache_byname, item)) != NULL) {
|
if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) {
|
||||||
pw_delref_item(node->data);
|
pw_delref_item(node->data);
|
||||||
node->data = item;
|
node->data = &pwitem->cache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item->refcnt++;
|
pwitem->cache.refcnt++;
|
||||||
debug_return_ptr(pw);
|
debug_return_ptr(pw);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,13 +469,13 @@ make_gritem(const struct group *gr, const char *name)
|
|||||||
{
|
{
|
||||||
char *cp;
|
char *cp;
|
||||||
size_t nsize, psize, nmem, total, len;
|
size_t nsize, psize, nmem, total, len;
|
||||||
struct cache_item *item;
|
struct cache_item_gr *gritem;
|
||||||
struct group *newgr;
|
struct group *newgr;
|
||||||
debug_decl(make_gritem, SUDO_DEBUG_NSS)
|
debug_decl(make_gritem, SUDO_DEBUG_NSS)
|
||||||
|
|
||||||
/* Allocate in one big chunk for easy freeing. */
|
/* Allocate in one big chunk for easy freeing. */
|
||||||
nsize = psize = nmem = 0;
|
nsize = psize = nmem = 0;
|
||||||
total = sizeof(struct cache_item) + sizeof(struct group);
|
total = sizeof(*gritem);
|
||||||
FIELD_SIZE(gr, gr_name, nsize);
|
FIELD_SIZE(gr, gr_name, nsize);
|
||||||
FIELD_SIZE(gr, gr_passwd, psize);
|
FIELD_SIZE(gr, gr_passwd, psize);
|
||||||
if (gr->gr_mem) {
|
if (gr->gr_mem) {
|
||||||
@@ -470,17 +487,16 @@ make_gritem(const struct group *gr, const char *name)
|
|||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
total += strlen(name) + 1;
|
total += strlen(name) + 1;
|
||||||
|
|
||||||
item = ecalloc(1, total);
|
gritem = ecalloc(1, total);
|
||||||
cp = (char *) item + sizeof(struct cache_item);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy in group contents and make strings relative to space
|
* Copy in group contents and make strings relative to space
|
||||||
* at the end of the buffer. Note that gr_mem must come
|
* at the end of the buffer. Note that gr_mem must come
|
||||||
* immediately after struct group to guarantee proper alignment.
|
* immediately after struct group to guarantee proper alignment.
|
||||||
*/
|
*/
|
||||||
newgr = (struct group *)cp;
|
newgr = &gritem->gr;
|
||||||
memcpy(newgr, gr, sizeof(struct group));
|
memcpy(newgr, gr, sizeof(*gr));
|
||||||
cp += sizeof(struct group);
|
cp = (char *)(gritem + 1);
|
||||||
if (gr->gr_mem) {
|
if (gr->gr_mem) {
|
||||||
newgr->gr_mem = (char **)cp;
|
newgr->gr_mem = (char **)cp;
|
||||||
cp += sizeof(char *) * nmem;
|
cp += sizeof(char *) * nmem;
|
||||||
@@ -498,14 +514,14 @@ make_gritem(const struct group *gr, const char *name)
|
|||||||
/* Set key and datum. */
|
/* Set key and datum. */
|
||||||
if (name != NULL) {
|
if (name != NULL) {
|
||||||
memcpy(cp, name, strlen(name) + 1);
|
memcpy(cp, name, strlen(name) + 1);
|
||||||
item->k.name = cp;
|
gritem->cache.k.name = cp;
|
||||||
} else {
|
} else {
|
||||||
item->k.gid = gr->gr_gid;
|
gritem->cache.k.gid = gr->gr_gid;
|
||||||
}
|
}
|
||||||
item->d.gr = newgr;
|
gritem->cache.d.gr = newgr;
|
||||||
item->refcnt = 1;
|
gritem->cache.refcnt = 1;
|
||||||
|
|
||||||
debug_return_ptr(item);
|
debug_return_ptr(&gritem->cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_UTMPX_H
|
#ifdef HAVE_UTMPX_H
|
||||||
@@ -527,7 +543,7 @@ make_grlist_item(const char *user, GETGROUPS_T *gids, int ngids)
|
|||||||
{
|
{
|
||||||
char *cp;
|
char *cp;
|
||||||
size_t i, nsize, ngroups, total, len;
|
size_t i, nsize, ngroups, total, len;
|
||||||
struct cache_item *item;
|
struct cache_item_grlist *grlitem;
|
||||||
struct group_list *grlist;
|
struct group_list *grlist;
|
||||||
struct group *grp;
|
struct group *grp;
|
||||||
debug_decl(make_grlist_item, SUDO_DEBUG_NSS)
|
debug_decl(make_grlist_item, SUDO_DEBUG_NSS)
|
||||||
@@ -538,22 +554,21 @@ make_grlist_item(const char *user, GETGROUPS_T *gids, int ngids)
|
|||||||
|
|
||||||
/* Allocate in one big chunk for easy freeing. */
|
/* Allocate in one big chunk for easy freeing. */
|
||||||
nsize = strlen(user) + 1;
|
nsize = strlen(user) + 1;
|
||||||
total = sizeof(struct cache_item) + sizeof(struct group_list) + nsize;
|
total = sizeof(*grlitem) + nsize;
|
||||||
total += sizeof(char *) * ngids;
|
total += sizeof(char *) * ngids;
|
||||||
total += sizeof(gid_t *) * ngids;
|
total += sizeof(gid_t *) * ngids;
|
||||||
total += GROUPNAME_LEN * ngids;
|
total += GROUPNAME_LEN * ngids;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
item = ecalloc(1, total);
|
grlitem = ecalloc(1, total);
|
||||||
cp = (char *) item + sizeof(struct cache_item);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy in group list and make pointers relative to space
|
* Copy in group list and make pointers relative to space
|
||||||
* at the end of the buffer. Note that the groups array must come
|
* at the end of the buffer. Note that the groups array must come
|
||||||
* immediately after struct group to guarantee proper alignment.
|
* immediately after struct group to guarantee proper alignment.
|
||||||
*/
|
*/
|
||||||
grlist = (struct group_list *)cp;
|
grlist = &grlitem->grlist;
|
||||||
cp += sizeof(struct group_list);
|
cp = (char *)(grlitem + 1);
|
||||||
grlist->groups = (char **)cp;
|
grlist->groups = (char **)cp;
|
||||||
cp += sizeof(char *) * ngids;
|
cp += sizeof(char *) * ngids;
|
||||||
grlist->gids = (gid_t *)cp;
|
grlist->gids = (gid_t *)cp;
|
||||||
@@ -561,9 +576,9 @@ again:
|
|||||||
|
|
||||||
/* Set key and datum. */
|
/* Set key and datum. */
|
||||||
memcpy(cp, user, nsize);
|
memcpy(cp, user, nsize);
|
||||||
item->k.name = cp;
|
grlitem->cache.k.name = cp;
|
||||||
item->d.grlist = grlist;
|
grlitem->cache.d.grlist = grlist;
|
||||||
item->refcnt = 1;
|
grlitem->cache.refcnt = 1;
|
||||||
cp += nsize;
|
cp += nsize;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -580,9 +595,9 @@ again:
|
|||||||
for (i = 0; i < ngids; i++) {
|
for (i = 0; i < ngids; i++) {
|
||||||
if ((grp = sudo_getgrgid(gids[i])) != NULL) {
|
if ((grp = sudo_getgrgid(gids[i])) != NULL) {
|
||||||
len = strlen(grp->gr_name) + 1;
|
len = strlen(grp->gr_name) + 1;
|
||||||
if (cp - (char *)item + len > total) {
|
if (cp - (char *)grlitem + len > total) {
|
||||||
total += len + GROUPNAME_LEN;
|
total += len + GROUPNAME_LEN;
|
||||||
efree(item);
|
efree(grlitem);
|
||||||
gr_delref(grp);
|
gr_delref(grp);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
@@ -598,7 +613,7 @@ again:
|
|||||||
aix_restoreauthdb();
|
aix_restoreauthdb();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
debug_return_ptr(item);
|
debug_return_ptr(&grlitem->cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -710,7 +725,7 @@ done:
|
|||||||
struct group *
|
struct group *
|
||||||
sudo_fakegrnam(const char *group)
|
sudo_fakegrnam(const char *group)
|
||||||
{
|
{
|
||||||
struct cache_item *item;
|
struct cache_item_gr *gritem;
|
||||||
struct group *gr;
|
struct group *gr;
|
||||||
struct rbnode *node;
|
struct rbnode *node;
|
||||||
size_t len, namelen;
|
size_t len, namelen;
|
||||||
@@ -718,34 +733,34 @@ sudo_fakegrnam(const char *group)
|
|||||||
debug_decl(sudo_fakegrnam, SUDO_DEBUG_NSS)
|
debug_decl(sudo_fakegrnam, SUDO_DEBUG_NSS)
|
||||||
|
|
||||||
namelen = strlen(group);
|
namelen = strlen(group);
|
||||||
len = sizeof(*item) + sizeof(*gr) + namelen + 1;
|
len = sizeof(*gritem) + namelen + 1;
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
item = ecalloc(1, len);
|
gritem = ecalloc(1, len);
|
||||||
gr = (struct group *) ((char *)item + sizeof(*item));
|
gr = &gritem->gr;
|
||||||
gr->gr_gid = (gid_t) atoi(group + 1);
|
gr->gr_gid = (gid_t) atoi(group + 1);
|
||||||
gr->gr_name = (char *)gr + sizeof(struct group);
|
gr->gr_name = (char *)(gritem + 1);
|
||||||
memcpy(gr->gr_name, group, namelen + 1);
|
memcpy(gr->gr_name, group, namelen + 1);
|
||||||
|
|
||||||
item->refcnt = 1;
|
gritem->cache.refcnt = 1;
|
||||||
item->d.gr = gr;
|
gritem->cache.d.gr = gr;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
/* Store by gid, overwriting cached version. */
|
/* Store by gid, overwriting cached version. */
|
||||||
item->k.gid = gr->gr_gid;
|
gritem->cache.k.gid = gr->gr_gid;
|
||||||
if ((node = rbinsert(grcache_bygid, item)) != NULL) {
|
if ((node = rbinsert(grcache_bygid, &gritem->cache)) != NULL) {
|
||||||
gr_delref_item(node->data);
|
gr_delref_item(node->data);
|
||||||
node->data = item;
|
node->data = &gritem->cache;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Store by name, overwriting cached version. */
|
/* Store by name, overwriting cached version. */
|
||||||
item->k.name = gr->gr_name;
|
gritem->cache.k.name = gr->gr_name;
|
||||||
if ((node = rbinsert(grcache_byname, item)) != NULL) {
|
if ((node = rbinsert(grcache_byname, &gritem->cache)) != NULL) {
|
||||||
gr_delref_item(node->data);
|
gr_delref_item(node->data);
|
||||||
node->data = item;
|
node->data = &gritem->cache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item->refcnt++;
|
gritem->cache.refcnt++;
|
||||||
debug_return_ptr(gr);
|
debug_return_ptr(gr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user