#include <grp.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include "compat_common.h"
static DEFINE_NSS_DB_ROOT(db_root);
static void
_nss_initf_group_compat(p)
nss_db_params_t *p;
{
p->name = NSS_DBNAM_GROUP;
p->config_name = NSS_DBNAM_GROUP_COMPAT;
p->default_config = NSS_DEFCONF_GROUP_COMPAT;
}
int
validate_group_ids(char *line, int *linelenp, int buflen, int extra_chars)
{
char *linep, *limit, *gidp;
ulong_t gid;
int oldgidlen, idlen;
int linelen = *linelenp, newlinelen;
if (linelen == 0 || *line == '+' || *line == '-')
return (NSS_STR_PARSE_SUCCESS);
linep = line;
limit = line + linelen;
while (linep < limit && *linep++ != ':')
continue;
while (linep < limit && *linep++ != ':')
continue;
if (linep == limit)
return (NSS_STR_PARSE_PARSE);
gidp = linep;
gid = strtoul(gidp, (char **)&linep, 10);
oldgidlen = linep - gidp;
if (linep >= limit || oldgidlen == 0)
return (NSS_STR_PARSE_PARSE);
if (gid <= MAXUID)
return (NSS_STR_PARSE_SUCCESS);
idlen = snprintf(NULL, 0, "%u", GID_NOBODY);
newlinelen = linelen + idlen - oldgidlen;
if (newlinelen + extra_chars > buflen)
return (NSS_STR_PARSE_ERANGE);
(void) bcopy(linep, gidp + idlen, limit - linep + extra_chars);
(void) snprintf(gidp, idlen + 1, "%u", GID_NOBODY);
*(gidp + idlen) = ':';
*linelenp = newlinelen;
return (NSS_STR_PARSE_SUCCESS);
}
static const char *
get_grname(argp)
nss_XbyY_args_t *argp;
{
struct group *g = (struct group *)argp->returnval;
return (g->gr_name);
}
static int
check_grname(argp)
nss_XbyY_args_t *argp;
{
struct group *g = (struct group *)argp->returnval;
return (strcmp(g->gr_name, argp->key.name) == 0);
}
static nss_status_t
getbyname(be, a)
compat_backend_ptr_t be;
void *a;
{
nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
return (_nss_compat_XY_all(be, argp, check_grname,
NSS_DBOP_GROUP_BYNAME));
}
static int
check_grgid(argp)
nss_XbyY_args_t *argp;
{
struct group *g = (struct group *)argp->returnval;
return (g->gr_gid == argp->key.gid);
}
static nss_status_t
getbygid(be, a)
compat_backend_ptr_t be;
void *a;
{
nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
if (argp->key.gid > MAXUID)
return (NSS_NOTFOUND);
return (_nss_compat_XY_all(be, argp, check_grgid,
NSS_DBOP_GROUP_BYGID));
}
static nss_status_t
getbymember(be, a)
compat_backend_ptr_t be;
void *a;
{
struct nss_groupsbymem *argp = (struct nss_groupsbymem *)a;
int numgids = argp->numgids;
int maxgids = argp->maxgids;
gid_t *gid_array = argp->gid_array;
struct nss_XbyY_args grargs;
struct group *g;
nss_XbyY_buf_t *gb = NULL, *b = NULL;
if (numgids >= maxgids) {
return (NSS_SUCCESS);
}
b = NSS_XbyY_ALLOC(&gb, sizeof (struct group), NSS_BUFLEN_GROUP);
if (b == 0)
return (NSS_UNAVAIL);
NSS_XbyY_INIT(&grargs, gb->result, gb->buffer, gb->buflen,
argp->str2ent);
g = (struct group *)gb->result;
(void) _nss_compat_setent(be, 0);
while (_nss_compat_getent(be, &grargs) == NSS_SUCCESS) {
char **mem;
if (grargs.returnval == 0) {
continue;
}
for (mem = g->gr_mem; *mem != 0; mem++) {
if (strcmp(*mem, argp->username) == 0) {
int gid = g->gr_gid;
int i;
for (i = 0; i < numgids; i++) {
if (gid == gid_array[i]) {
break;
}
}
if (i == numgids) {
gid_array[numgids++] = gid;
argp->numgids = numgids;
if (numgids >= maxgids) {
(void) _nss_compat_endent(be,
0);
NSS_XbyY_FREE(&gb);
return (NSS_SUCCESS);
}
break;
}
}
}
}
(void) _nss_compat_endent(be, 0);
NSS_XbyY_FREE(&gb);
return (NSS_NOTFOUND);
}
static int
merge_grents(be, argp, fields)
compat_backend_ptr_t be;
nss_XbyY_args_t *argp;
const char **fields;
{
struct group *g = (struct group *)argp->buf.result;
char *buf;
char *s;
int parsestat;
int dlen;
if (fields[1] == 0 && fields[3] == 0 &&
be->return_string_data != 1) {
return (NSS_STR_PARSE_SUCCESS);
}
if ((buf = malloc(NSS_LINELEN_GROUP)) == 0) {
return (NSS_STR_PARSE_PARSE);
}
s = buf;
(void) snprintf(s, NSS_LINELEN_GROUP, "%s:%s:%u:",
g->gr_name,
fields[1] != 0 ? fields[1] : g->gr_passwd,
g->gr_gid);
s += strlen(s);
if (fields[3] != 0) {
(void) strcpy(s, fields[3]);
s += strlen(s);
} else {
char **memp;
for (memp = g->gr_mem; *memp != 0; memp++) {
size_t len = strlen(*memp);
if (s + len + 1 <= buf + NSS_LINELEN_GROUP) {
if (memp != g->gr_mem) {
*s++ = ',';
}
(void) memcpy(s, *memp, len);
s += len;
} else {
free(buf);
return (NSS_STR_PARSE_ERANGE);
}
}
}
dlen = s - buf;
if (be->return_string_data == 1) {
argp->buf.result = NULL;
if (dlen > argp->buf.buflen) {
parsestat = NSS_STR_PARSE_ERANGE;
} else {
(void) strncpy(argp->buf.buffer, buf, dlen);
argp->returnval = argp->buf.buffer;
argp->returnlen = dlen;
parsestat = NSS_SUCCESS;
}
} else {
parsestat = (*argp->str2ent)(buf, dlen,
argp->buf.result,
argp->buf.buffer,
argp->buf.buflen);
}
free(buf);
return (parsestat);
}
static compat_backend_op_t group_ops[] = {
_nss_compat_destr,
_nss_compat_endent,
_nss_compat_setent,
_nss_compat_getent,
getbyname,
getbygid,
getbymember
};
nss_backend_t *
_nss_compat_group_constr(dummy1, dummy2, dummy3)
const char *dummy1, *dummy2, *dummy3;
{
return (_nss_compat_constr(group_ops,
sizeof (group_ops) / sizeof (group_ops[0]),
GF_PATH,
NSS_LINELEN_GROUP,
&db_root,
_nss_initf_group_compat,
0,
get_grname,
merge_grents));
}