#include <grp.h>
#include "ldap_common.h"
#include <string.h>
#define _CRYPT "{CRYPT}"
#define _NO_PASSWD_VAL ""
#define _G_NAME "cn"
#define _G_GID "gidnumber"
#define _G_PASSWD "userpassword"
#define _G_MEMUID "memberuid"
#define _G_MEM_DN "member"
#define _F_GETGRNAM "(&(objectClass=posixGroup)(cn=%s))"
#define _F_GETGRNAM_SSD "(&(%%s)(cn=%s))"
#define _F_GETGRGID "(&(objectClass=posixGroup)(gidNumber=%u))"
#define _F_GETGRGID_SSD "(&(%%s)(gidNumber=%u))"
#define _F_GETGRMEM "(&(objectClass=posixGroup)" \
"(|(memberUid=%s)(member=%s)))"
#define _F_GETGRMEM_SSD "(&(%%s)" \
"(|(memberUid=%s)(member=%s)))"
static const char *gr_attrs[] = {
_G_NAME,
_G_GID,
_G_PASSWD,
_G_MEMUID,
_G_MEM_DN,
(char *)NULL
};
static int
getmembers_UID(char **bufpp, int *lenp, ns_ldap_attr_t *members);
static int
getmembers_DN(char **bufpp, int *lenp, ns_ldap_attr_t *members);
static int
_nss_ldap_group2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
{
int i;
int nss_result;
int buflen = 0, len;
char *buffer = NULL;
ns_ldap_result_t *result = be->result;
char **gname, **passwd, **gid, *password, *end;
char gid_nobody[NOBODY_STR_LEN];
char *gid_nobody_v[1];
ns_ldap_attr_t *members;
(void) snprintf(gid_nobody, sizeof (gid_nobody), "%u", GID_NOBODY);
gid_nobody_v[0] = gid_nobody;
if (result == NULL)
return (NSS_STR_PARSE_PARSE);
buflen = argp->buf.buflen;
if (argp->buf.result != NULL) {
if ((be->buffer = calloc(1, buflen)) == NULL) {
nss_result = NSS_STR_PARSE_PARSE;
goto result_grp2str;
}
buffer = be->buffer;
} else
buffer = argp->buf.buffer;
nss_result = NSS_STR_PARSE_SUCCESS;
(void) memset(buffer, 0, buflen);
gname = __ns_ldap_getAttr(result->entry, _G_NAME);
if (gname == NULL || gname[0] == NULL || (strlen(gname[0]) < 1)) {
nss_result = NSS_STR_PARSE_PARSE;
goto result_grp2str;
}
passwd = __ns_ldap_getAttr(result->entry, _G_PASSWD);
if (passwd == NULL || passwd[0] == NULL || (strlen(passwd[0]) == 0)) {
password = _NO_PASSWD_VAL;
} else {
if (strncasecmp(passwd[0], _CRYPT, strlen(_CRYPT)) == 0)
password = passwd[0] + strlen(_CRYPT);
else
password = passwd[0];
}
gid = __ns_ldap_getAttr(result->entry, _G_GID);
if (gid == NULL || gid[0] == NULL || (strlen(gid[0]) < 1)) {
nss_result = NSS_STR_PARSE_PARSE;
goto result_grp2str;
}
if (strtoul(gid[0], &end, 10) > MAXUID)
gid = gid_nobody_v;
len = snprintf(buffer, buflen, "%s:%s:%s:", gname[0], password, gid[0]);
TEST_AND_ADJUST(len, buffer, buflen, result_grp2str);
members = __ns_ldap_getAttrStruct(result->entry, _G_MEMUID);
if (members != NULL && members->attrvalue != NULL) {
nss_result = getmembers_UID(&buffer, &buflen, members);
if (nss_result != 0)
goto result_grp2str;
}
members = __ns_ldap_getAttrStruct(result->entry, _G_MEM_DN);
if (members != NULL && members->attrvalue != NULL) {
nss_result = getmembers_DN(&buffer, &buflen, members);
if (nss_result != 0)
goto result_grp2str;
}
if (argp->buf.result != NULL)
be->buflen = strlen(be->buffer);
result_grp2str:
(void) __ns_ldap_freeResult(&be->result);
return (nss_result);
}
static int
getmembers_UID(char **bufpp, int *lenp, ns_ldap_attr_t *members)
{
char *member_str, *strtok_state;
char *buffer;
int buflen;
int i, len;
int nss_result = 0;
int firsttime;
buffer = *bufpp;
buflen = *lenp;
firsttime = (buffer[-1] == ':');
for (i = 0; i < members->value_count; i++) {
member_str = members->attrvalue[i];
if (member_str == NULL)
goto out;
#ifdef DEBUG
(void) fprintf(stdout, "getmembers_UID: uid=<%s>\n",
member_str);
#endif
if (member_str[0] == '\0' ||
strpbrk(member_str, " ,:=") != NULL)
continue;
if (firsttime) {
len = snprintf(buffer, buflen, "%s", member_str);
firsttime = 0;
} else {
len = snprintf(buffer, buflen, ",%s", member_str);
}
TEST_AND_ADJUST(len, buffer, buflen, out);
}
out:
*bufpp = buffer;
*lenp = buflen;
return (nss_result);
}
static int
getmembers_DN(char **bufpp, int *lenp, ns_ldap_attr_t *members)
{
ns_ldap_error_t *error = NULL;
char *member_dn, *member_uid;
char *buffer;
int buflen;
int i, len;
int nss_result = 0;
int firsttime;
buffer = *bufpp;
buflen = *lenp;
firsttime = (buffer[-1] == ':');
for (i = 0; i < members->value_count; i++) {
member_dn = members->attrvalue[i];
if (member_dn == NULL)
goto out;
#ifdef DEBUG
(void) fprintf(stdout, "getmembers_DN: dn=%s\n",
member_dn);
#endif
if (member_dn[0] == '\0')
continue;
if (__ns_ldap_dn2uid(member_dn,
&member_uid, NULL, &error) != NS_LDAP_SUCCESS) {
(void) __ns_ldap_freeError(&error);
error = NULL;
continue;
}
#ifdef DEBUG
(void) fprintf(stdout, "getmembers_DN: uid=<%s>\n",
member_uid);
#endif
if (member_uid[0] == '\0' ||
strpbrk(member_uid, " ,:=") != NULL) {
free(member_uid);
continue;
}
if (firsttime) {
len = snprintf(buffer, buflen, "%s", member_uid);
firsttime = 0;
} else {
len = snprintf(buffer, buflen, ",%s", member_uid);
}
free(member_uid);
TEST_AND_ADJUST(len, buffer, buflen, out);
}
out:
*bufpp = buffer;
*lenp = buflen;
return (nss_result);
}
static nss_status_t
getbynam(ldap_backend_ptr be, void *a)
{
nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
char searchfilter[SEARCHFILTERLEN];
char userdata[SEARCHFILTERLEN];
char groupname[SEARCHFILTERLEN];
int ret;
if (_ldap_filter_name(groupname, argp->key.name, sizeof (groupname)) !=
0)
return ((nss_status_t)NSS_NOTFOUND);
ret = snprintf(searchfilter, sizeof (searchfilter),
_F_GETGRNAM, groupname);
if (ret >= sizeof (searchfilter) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
ret = snprintf(userdata, sizeof (userdata), _F_GETGRNAM_SSD, groupname);
if (ret >= sizeof (userdata) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
return ((nss_status_t)_nss_ldap_lookup(be, argp,
_GROUP, searchfilter, NULL, _merge_SSD_filter, userdata));
}
static nss_status_t
getbygid(ldap_backend_ptr be, void *a)
{
nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
char searchfilter[SEARCHFILTERLEN];
char userdata[SEARCHFILTERLEN];
int ret;
if (argp->key.uid > MAXUID)
return ((nss_status_t)NSS_NOTFOUND);
ret = snprintf(searchfilter, sizeof (searchfilter),
_F_GETGRGID, argp->key.uid);
if (ret >= sizeof (searchfilter) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
ret = snprintf(userdata, sizeof (userdata),
_F_GETGRGID_SSD, argp->key.uid);
if (ret >= sizeof (userdata) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
return ((nss_status_t)_nss_ldap_lookup(be, argp,
_GROUP, searchfilter, NULL, _merge_SSD_filter, userdata));
}
static const char *grbymem_attrs[] = {
_G_NAME,
_G_GID,
(char *)NULL
};
static nss_status_t
getbymember(ldap_backend_ptr be, void *a)
{
ns_ldap_error_t *error = NULL;
int i, j, k;
int gcnt = (int)0;
char **groupvalue;
nss_status_t lstat;
struct nss_groupsbymem *argp = (struct nss_groupsbymem *)a;
char searchfilter[SEARCHFILTERLEN];
char userdata[SEARCHFILTERLEN];
char name[SEARCHFILTERLEN];
char escdn[SEARCHFILTERLEN];
ns_ldap_result_t *result;
ns_ldap_entry_t *curEntry;
char *dn;
gid_t gid;
int ret1, ret2;
if (strcmp(argp->username, "") == 0 ||
strcmp(argp->username, "root") == 0)
return ((nss_status_t)NSS_NOTFOUND);
if (_ldap_filter_name(name, argp->username, sizeof (name)) != 0)
return ((nss_status_t)NSS_NOTFOUND);
lstat = __ns_ldap_uid2dn(name, &dn, NULL, &error);
if (lstat != (nss_status_t)NS_LDAP_SUCCESS) {
(void) __ns_ldap_freeError(&error);
dn = name;
}
ret1 = snprintf(searchfilter, sizeof (searchfilter),
_F_GETGRMEM, name, dn);
ret2 = snprintf(userdata, sizeof (userdata),
_F_GETGRMEM_SSD, name, dn);
if (dn != name)
free(dn);
if (ret1 >= sizeof (searchfilter) || ret1 < 0)
return ((nss_status_t)NSS_NOTFOUND);
if (ret2 >= sizeof (userdata) || ret2 < 0)
return ((nss_status_t)NSS_NOTFOUND);
lstat = (nss_status_t)_nss_ldap_nocb_lookup(be, NULL,
_GROUP, searchfilter, grbymem_attrs,
_merge_SSD_filter, userdata);
if (lstat != (nss_status_t)NS_LDAP_SUCCESS)
return ((nss_status_t)lstat);
if (be->result == NULL)
return (NSS_NOTFOUND);
result = (ns_ldap_result_t *)be->result;
curEntry = (ns_ldap_entry_t *)result->entry;
gcnt = (int)argp->numgids;
for (i = 0; i < result->entries_count; i++) {
groupvalue = __ns_ldap_getAttr(curEntry, _G_GID);
if (groupvalue == NULL || groupvalue[0] == NULL) {
goto next_group;
}
errno = 0;
gid = (gid_t)strtol(groupvalue[0], (char **)NULL, 10);
if (errno != 0)
goto next_group;
if (argp->numgids < argp->maxgids) {
for (k = 0; k < argp->numgids; k++) {
if (argp->gid_array[k] == gid) {
goto next_group;
}
}
argp->gid_array[argp->numgids++] = gid;
}
next_group:
curEntry = curEntry->next;
}
(void) __ns_ldap_freeResult((ns_ldap_result_t **)&be->result);
if (gcnt == argp->numgids)
return ((nss_status_t)NSS_NOTFOUND);
return ((nss_status_t)((argp->numgids == argp->maxgids)
? NSS_SUCCESS
: NSS_NOTFOUND));
}
static ldap_backend_op_t gr_ops[] = {
_nss_ldap_destr,
_nss_ldap_endent,
_nss_ldap_setent,
_nss_ldap_getent,
getbynam,
getbygid,
getbymember
};
nss_backend_t *
_nss_ldap_group_constr(const char *dummy1, const char *dummy2,
const char *dummy3)
{
return ((nss_backend_t *)_nss_ldap_constr(gr_ops,
sizeof (gr_ops)/sizeof (gr_ops[0]), _GROUP, gr_attrs,
_nss_ldap_group2str));
}