1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-25 23:21:54 +03:00

nss_wrapper: add support for groups and return EPERM in initgroups()

The NSS_WRAPPER_GROUP envvar should point to
the /etc/group style file.

Note: NSS_WRAPPER_PASSWD and NSS_WRAPPER_GROUP both
      need non-empty values to enable NSS Wrapper
      support.

metze

git-svn-id: svn+ssh://svn.samba.org/data/svn/samba/branches/SAMBA_4_0@25836 0c0555d6-39d7-0310-84fc-f1cc0bd64818
(This used to be commit 6abc84a564)
This commit is contained in:
metze 2007-11-05 15:41:23 +00:00 committed by Stefan Metzmacher
parent d2397d7b1b
commit 419c600897

View File

@ -137,6 +137,20 @@ struct nwrap_pw nwrap_pw_global;
static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line);
static void nwrap_pw_unload(struct nwrap_cache *nwrap);
struct nwrap_gr {
struct nwrap_cache *cache;
struct group *list;
int num;
int idx;
};
struct nwrap_cache __nwrap_cache_gr;
struct nwrap_gr nwrap_gr_global;
static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line);
static void nwrap_gr_unload(struct nwrap_cache *nwrap);
static void nwrap_init(void)
{
static bool initialized;
@ -151,6 +165,14 @@ static void nwrap_init(void)
nwrap_pw_global.cache->private_data = &nwrap_pw_global;
nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
nwrap_pw_global.cache->unload = nwrap_pw_unload;
nwrap_gr_global.cache = &__nwrap_cache_gr;
nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
nwrap_gr_global.cache->fd = -1;
nwrap_gr_global.cache->private_data = &nwrap_gr_global;
nwrap_gr_global.cache->parse_line = nwrap_gr_parse_line;
nwrap_gr_global.cache->unload = nwrap_gr_unload;
}
static bool nwrap_enabled(void)
@ -163,6 +185,12 @@ static bool nwrap_enabled(void)
if (nwrap_pw_global.cache->path[0] == '\0') {
return false;
}
if (!nwrap_gr_global.cache->path) {
return false;
}
if (nwrap_gr_global.cache->path[0] == '\0') {
return false;
}
return true;
}
@ -522,6 +550,198 @@ static int nwrap_pw_copy_r(const struct passwd *src, struct passwd *dst,
return 0;
}
/*
* the caller has to call nwrap_unload() on failure
*/
static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
{
struct nwrap_gr *nwrap_gr;
char *c;
char *p;
char *e;
struct group *gr;
size_t list_size;
unsigned nummem;
nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
gr = (struct group *)realloc(nwrap_gr->list, list_size);
if (!gr) {
NWRAP_ERROR(("%s:realloc failed\n",__location__));
return false;
}
nwrap_gr->list = gr;
gr = &nwrap_gr->list[nwrap_gr->num];
c = line;
/* name */
p = strchr(c, ':');
if (!p) {
NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
__location__, line, c));
return false;
}
*p = '\0';
p++;
gr->gr_name = c;
c = p;
NWRAP_VERBOSE(("name[%s]\n", gr->gr_name));
/* password */
p = strchr(c, ':');
if (!p) {
NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
__location__, line, c));
return false;
}
*p = '\0';
p++;
gr->gr_passwd = c;
c = p;
NWRAP_VERBOSE(("password[%s]\n", gr->gr_passwd));
/* gid */
p = strchr(c, ':');
if (!p) {
NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
__location__, line, c));
return false;
}
*p = '\0';
p++;
e = NULL;
gr->gr_gid = (gid_t)strtoul(c, &e, 10);
if (c == e) {
NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
__location__, line, c, strerror(errno)));
return false;
}
if (e == NULL) {
NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
__location__, line, c, strerror(errno)));
return false;
}
if (e[0] != '\0') {
NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
__location__, line, c, strerror(errno)));
return false;
}
c = p;
NWRAP_VERBOSE(("gid[%u]\n", gr->gr_gid));
/* members */
gr->gr_mem = (char **)malloc(sizeof(char *));
if (!gr->gr_mem) {
NWRAP_ERROR(("%s:calloc failed\n",__location__));
return false;
}
gr->gr_mem[0] = NULL;
for(nummem=0; p; nummem++) {
char **m;
size_t m_size;
c = p;
p = strchr(c, ',');
if (p) {
*p = '\0';
p++;
}
if (strlen(c) == 0) {
break;
}
m_size = sizeof(char *) * (nummem+2);
m = (char **)realloc(gr->gr_mem, m_size);
if (!m) {
NWRAP_ERROR(("%s:realloc(%u) failed\n",
__location__, m_size));
return false;
}
gr->gr_mem = m;
gr->gr_mem[nummem] = c;
gr->gr_mem[nummem+1] = NULL;
NWRAP_VERBOSE(("member[%u]: '%s'\n", nummem, gr->gr_mem[nummem]));
}
NWRAP_DEBUG(("add group[%s:%s:%u:] with %u members\n",
gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem));
nwrap_gr->num++;
return true;
}
static void nwrap_gr_unload(struct nwrap_cache *nwrap)
{
int i;
struct nwrap_gr *nwrap_gr;
nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
if (nwrap_gr->list) {
for (i=0; i < nwrap_gr->num; i++) {
if (nwrap_gr->list[i].gr_mem) {
free(nwrap_gr->list[i].gr_mem);
}
}
free(nwrap_gr->list);
}
nwrap_gr->list = NULL;
nwrap_gr->num = 0;
nwrap_gr->idx = 0;
}
static int nwrap_gr_copy_r(const struct group *src, struct group *dst,
char *buf, size_t buflen, struct group **destp)
{
char *first;
char **lastm;
char *last;
off_t ofsb;
off_t ofsm;
off_t ofs;
unsigned i;
first = src->gr_name;
lastm = src->gr_mem;
while (*lastm) lastm++;
last = *lastm;
while (*last) last++;
ofsb = PTR_DIFF(last + 1, first);
ofsm = PTR_DIFF(lastm + 1, src->gr_mem);
if ((ofsb + ofsm) > buflen) {
return ERANGE;
}
memcpy(buf, first, ofsb);
memcpy(buf + ofsb, src->gr_mem, ofsm);
ofs = PTR_DIFF(src->gr_name, first);
dst->gr_name = buf + ofs;
ofs = PTR_DIFF(src->gr_passwd, first);
dst->gr_passwd = buf + ofs;
dst->gr_gid = src->gr_gid;
dst->gr_mem = (char **)(buf + ofsb);
for (i=0; src->gr_mem[i]; i++) {
ofs = PTR_DIFF(src->gr_mem[i], first);
dst->gr_mem[i] = buf + ofs;
}
return 0;
}
/* user functions */
_PUBLIC_ struct passwd *nwrap_getpwnam(const char *name)
{
@ -684,50 +904,171 @@ _PUBLIC_ void nwrap_endpwent(void)
/* misc functions */
_PUBLIC_ int nwrap_initgroups(const char *user, gid_t group)
{
return real_initgroups(user, group);
if (!nwrap_enabled()) {
return real_initgroups(user, group);
}
/* TODO: maybe we should also fake this... */
return EPERM;
}
/* group functions */
_PUBLIC_ struct group *nwrap_getgrnam(const char *name)
{
return real_getgrnam(name);
int i;
if (!nwrap_enabled()) {
return real_getgrnam(name);
}
nwrap_cache_reload(nwrap_gr_global.cache);
for (i=0; i<nwrap_gr_global.num; i++) {
if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) {
NWRAP_DEBUG(("%s: group[%s] found\n",
__location__, name));
return &nwrap_gr_global.list[i];
}
NWRAP_VERBOSE(("%s: group[%s] does not match [%s]\n",
__location__, name,
nwrap_gr_global.list[i].gr_name));
}
NWRAP_DEBUG(("%s: group[%s] not found\n", __location__, name));
errno = ENOENT;
return NULL;
}
_PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *gbuf,
char *buf, size_t buflen, struct group **gbufp)
_PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *grdst,
char *buf, size_t buflen, struct group **grdstp)
{
return real_getgrnam_r(name, gbuf, buf, buflen, gbufp);
struct group *gr;
if (!nwrap_enabled()) {
return real_getgrnam_r(name, grdst, buf, buflen, grdstp);
}
gr = nwrap_getgrnam(name);
if (!gr) {
if (errno == 0) {
return ENOENT;
}
return errno;
}
return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
}
_PUBLIC_ struct group *nwrap_getgrgid(gid_t gid)
{
return real_getgrgid(gid);
int i;
if (!nwrap_enabled()) {
return real_getgrgid(gid);
}
nwrap_cache_reload(nwrap_gr_global.cache);
for (i=0; i<nwrap_gr_global.num; i++) {
if (nwrap_gr_global.list[i].gr_gid == gid) {
NWRAP_DEBUG(("%s: gid[%u] found\n",
__location__, gid));
return &nwrap_gr_global.list[i];
}
NWRAP_VERBOSE(("%s: gid[%u] does not match [%u]\n",
__location__, gid,
nwrap_gr_global.list[i].gr_gid));
}
NWRAP_DEBUG(("%s: gid[%u] not found\n", __location__, gid));
errno = ENOENT;
return NULL;
}
_PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *gbuf,
char *buf, size_t buflen, struct group **gbufp)
_PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *grdst,
char *buf, size_t buflen, struct group **grdstp)
{
return real_getgrgid_r(gid, gbuf, buf, buflen, gbufp);
struct group *gr;
if (!nwrap_enabled()) {
return real_getgrgid_r(gid, grdst, buf, buflen, grdstp);
}
gr = nwrap_getgrgid(gid);
if (!gr) {
if (errno == 0) {
return ENOENT;
}
return errno;
}
return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
return ENOENT;
}
/* group enum functions */
_PUBLIC_ void nwrap_setgrent(void)
{
real_setgrent();
if (!nwrap_enabled()) {
real_setgrent();
}
nwrap_gr_global.idx = 0;
}
_PUBLIC_ struct group *nwrap_getgrent(void)
{
return real_getgrent();
struct group *gr;
if (!nwrap_enabled()) {
return real_getgrent();
}
if (nwrap_gr_global.idx == 0) {
nwrap_cache_reload(nwrap_gr_global.cache);
}
if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
errno = ENOENT;
return NULL;
}
gr = &nwrap_gr_global.list[nwrap_gr_global.idx++];
NWRAP_VERBOSE(("%s: return group[%s] gid[%u]\n",
__location__, gr->gr_name, gr->gr_gid));
return gr;
}
_PUBLIC_ int nwrap_getgrent_r(struct group *gbuf, char *buf,
size_t buflen, struct group **gbufp)
_PUBLIC_ int nwrap_getgrent_r(struct group *grdst, char *buf,
size_t buflen, struct group **grdstp)
{
return real_getgrent_r(gbuf, buf, buflen, gbufp);
struct group *gr;
if (!nwrap_enabled()) {
return real_getgrent_r(grdst, buf, buflen, grdstp);
}
gr = nwrap_getgrent();
if (!gr) {
if (errno == 0) {
return ENOENT;
}
return errno;
}
return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
}
_PUBLIC_ void nwrap_endgrent(void)
{
real_endgrent();
if (!nwrap_enabled()) {
real_endgrent();
}
nwrap_gr_global.idx = 0;
}