Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Varied fixes #19

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/nscd.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,7 @@
#define GRMEMCNT 5
#define GR_LEN 6

#define ISPWREQ(r) (r==GETPWBYNAME || r==GETPWBYUID)
#define ISGRPREQ(r) (r==GETGRBYNAME || r==GETGRBYGID)

#endif
1 change: 0 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ int main(int argc, char **argv)
if(!mod->nss_getgrgid_r) mod->nss_getgrgid_r = null_getgrgid_r;
mod->nss_initgroups_dyn = (nss_initgroups_dyn)get_fn(dll, "initgroups_dyn", service->service);
if(!mod->nss_initgroups_dyn) mod->nss_initgroups_dyn = null_initgroups_dyn;
dlclose(dll);

memcpy(mod->on_status, service->on_status, sizeof(mod->on_status));

Expand Down
62 changes: 33 additions & 29 deletions src/socket_handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <semaphore.h>
#include <ctype.h>
#include <limits.h>
#include <assert.h>
#include <stdbool.h>

#include "util.h"
#include "nss.h"
Expand Down Expand Up @@ -117,12 +119,14 @@ void socket_handle(int fd, int timeout, locale_t l, void *pthread_args)
}


if(full_read(n, (char*)buf, REQ_LEN * sizeof(uint32_t)) < 0) {
if(full_read(n, (char*)buf, sizeof buf) < 0) {
syslog(LOG_ERR, "error in read: %s", strerror_l(errno, l));
goto cleanup_fd;
}

if(buf[REQVERSION] != NSCDVERSION && buf[REQVERSION] == swap32(NSCDVERSION)) {
/* means our endianness doesn't match the requester's */
swap = 1;
for(int i = 0; i < REQ_LEN; i++)
buf[i] = swap32(buf[i]);
}
Expand Down Expand Up @@ -200,36 +204,37 @@ struct initgroups_res {
gid_t *grps;
};

enum nss_status nss_getkey(uint32_t reqtype, void *fn, void *key, void *res, char *buf, size_t n, int *ret)
static enum nss_status nss_getkey(uint32_t reqtype, struct mod_passwd *mod_passwd, struct mod_group *mod_group, void *key, void *res, char *buf, size_t n, int *ret)
{
nss_getgrnam_r fn_grnam;
nss_getgrgid_r fn_grgid;
nss_getpwnam_r fn_pwnam;
nss_getpwuid_r fn_pwuid;
int retval = NSS_STATUS_UNAVAIL;
struct initgroups_res *initgroups_res;

/* for debug only: guarantee the nss_getkey function is being used correctly */
if(ISPWREQ(reqtype)) assert(mod_passwd);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a comment above it explaining that this is for debugging only.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment now.

else assert(mod_group);

switch(reqtype) {
case GETPWBYNAME:
retval = ((nss_getpwnam_r)fn)((char*)key, (struct passwd*)res, buf, n, ret);
retval = mod_passwd->nss_getpwnam_r((char*)key, (struct passwd*)res, buf, n, ret);
break;
case GETPWBYUID:
retval = ((nss_getpwuid_r)fn)((uid_t)*(uint32_t*)key, (struct passwd*)res, buf, n, ret);
retval = mod_passwd->nss_getpwuid_r((uid_t)*(uint32_t*)key, (struct passwd*)res, buf, n, ret);
break;
case GETGRBYNAME:
retval = ((nss_getgrnam_r)fn)((char*)key, (struct group*)res, buf, n, ret);
retval = mod_group->nss_getgrnam_r((char*)key, (struct group*)res, buf, n, ret);
break;
case GETGRBYGID:
retval = ((nss_getgrgid_r)fn)((gid_t)*(uint32_t*)key, (struct group*)res, buf, n, ret);
retval = mod_group->nss_getgrgid_r((gid_t)*(uint32_t*)key, (struct group*)res, buf, n, ret);
break;
case GETINITGR:
initgroups_res = res;
initgroups_res->end = 0;
initgroups_res->alloc = NGROUPS_MAX + 1;
initgroups_res->grps = (gid_t*)malloc(sizeof(gid_t) * initgroups_res->alloc);
retval = ((nss_initgroups_dyn)fn)((char*)key, (gid_t)-1, &(initgroups_res->end), &(initgroups_res->alloc), &(initgroups_res->grps), UINT32_MAX, ret);
retval = mod_group->nss_initgroups_dyn((char*)key, (gid_t)-1, &(initgroups_res->end), &(initgroups_res->alloc), &(initgroups_res->grps), UINT32_MAX, ret);
break;
}
if(retval == NSS_STATUS_SUCCESS && (reqtype == GETPWBYNAME || reqtype == GETPWBYUID)) {
if(retval == NSS_STATUS_SUCCESS && ISPWREQ(reqtype)) {
struct passwd *pwd = res;
if(!pwd->pw_name) retval = NSS_STATUS_NOTFOUND;
#ifdef HAVE_PW_PASSWD
Expand All @@ -241,7 +246,7 @@ enum nss_status nss_getkey(uint32_t reqtype, void *fn, void *key, void *res, cha
if(!pwd->pw_dir) retval = NSS_STATUS_NOTFOUND;
if(!pwd->pw_shell) retval = NSS_STATUS_NOTFOUND;
}
if(retval == NSS_STATUS_SUCCESS && (reqtype == GETGRBYNAME || reqtype == GETGRBYGID)) {
if(retval == NSS_STATUS_SUCCESS && ISGRPREQ(reqtype)) {
struct group *grp = res;
if(!grp->gr_name) retval = NSS_STATUS_NOTFOUND;
#ifdef HAVE_GR_PASSWD
Expand All @@ -265,32 +270,31 @@ int return_result(int fd, int swap, uint32_t reqtype, void *key)
char *buf = 0;
size_t buf_len = 0;
long tmp;
void *fn;
bool using_passwd;

switch(reqtype) {
case GETPWBYNAME: case GETPWBYUID:
if(ISPWREQ(reqtype)) {
using_passwd = true;
l = list_head(&passwd_mods);
tmp = sysconf(_SC_GETPW_R_SIZE_MAX);
if(tmp < 0) buf_len = 4096;
else buf_len = tmp;
buf = malloc(buf_len);
if(!buf) return -1;
break;
case GETGRBYNAME: case GETGRBYGID: case GETINITGR:
} else {
using_passwd = false;
l = list_head(&group_mods);
tmp = sysconf(_SC_GETGR_R_SIZE_MAX);
if(tmp < 0) buf_len = 4096;
else buf_len = tmp;
buf = malloc(buf_len);
if(!buf) return -1;
break;
}
for(; l; l = list_next(l)) {
int ret;
int act;
enum nss_status status;
action *on_status;
if(reqtype == GETPWBYNAME || reqtype == GETPWBYUID) {
if(using_passwd) {
mod_passwd = list_ref(l, struct mod_passwd, link);
mod_group = 0;
} else {
Expand All @@ -299,27 +303,27 @@ int return_result(int fd, int swap, uint32_t reqtype, void *key)
}
do {
memset(&res, 0, sizeof(res));
fn =
reqtype == GETPWBYNAME ? (void*)mod_passwd->nss_getpwnam_r :
reqtype == GETPWBYUID ? (void*)mod_passwd->nss_getpwuid_r :
reqtype == GETGRBYNAME ? (void*)mod_group->nss_getgrnam_r :
reqtype == GETGRBYGID ? (void*)mod_group->nss_getgrgid_r :
(void*)mod_group->nss_initgroups_dyn;
status = nss_getkey(reqtype, fn, key, &res, buf, buf_len, &ret);
status = nss_getkey(reqtype, mod_passwd, mod_group, key, &res, buf, buf_len, &ret);
if(status == NSS_STATUS_TRYAGAIN && ret == ERANGE) {
size_t new_len;
char *new_buf;
if(ret == EAGAIN) break;
if(buf_len == SIZE_MAX) {
free(buf);
errno = ENOMEM;
return -1;
}
/* memory growth factor is 1.5x.
* to avoid overshooting SIZE_MAX and overflowing,
* we use the check below: buf_len > (2/3) * SIZE_MAX */
if(buf_len > SIZE_MAX - buf_len/2) {
new_len = SIZE_MAX;
} else {
/* buf_len * 1.5 */
new_len = buf_len + buf_len/2;
}
/* TODO: doesn't need to be a realloc,
* since we don't need to copy the memory;
* evaluate if it's better or worse than malloc+free */
new_buf = realloc(buf, new_len);
if(!new_buf) {
free(buf);
Expand All @@ -330,7 +334,7 @@ int return_result(int fd, int swap, uint32_t reqtype, void *key)
}
} while(status == NSS_STATUS_TRYAGAIN && ret == ERANGE);

on_status = mod_passwd ? mod_passwd->on_status : mod_group->on_status;
on_status = using_passwd ? mod_passwd->on_status : mod_group->on_status;
act = on_status[
status == NSS_STATUS_TRYAGAIN ? STS_TRYAGAIN :
status == NSS_STATUS_UNAVAIL ? STS_UNAVAIL :
Expand Down
2 changes: 1 addition & 1 deletion src/write_val.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

int write_pwd(int fd, int swap, struct passwd *pwd)
{
uint32_t head[9] = {
uint32_t head[PW_LEN] = {
NSCDVERSION
};
size_t namelen = 0, passwdlen = 0, gecoslen = 0, dirlen = 0, shelllen = 0;
Expand Down