summaryrefslogtreecommitdiff
path: root/usr/src/lib/nsswitch
diff options
context:
space:
mode:
authorPaul B. Henson <henson@acm.org>2012-10-01 18:01:32 -0700
committerRichard Lowe <richlowe@richlowe.net>2012-10-12 22:08:33 -0400
commit4c6ae46166796718de10c1839ffe0569daa48250 (patch)
tree4e0b386f7109360202fb6774ba4b086d6c65a705 /usr/src/lib/nsswitch
parent3cb02613df33d0be6e1b0ed7c2ecbf33525431d6 (diff)
downloadillumos-joyent-4c6ae46166796718de10c1839ffe0569daa48250.tar.gz
3177 LDAP client: support for uniqueMember attribute
Reviewed by: Milan Jurik <milan.jurik@xylab.cz> Approved by: Richard Lowe <richlowe@richlowe.net>
Diffstat (limited to 'usr/src/lib/nsswitch')
-rw-r--r--usr/src/lib/nsswitch/ldap/common/getgrent.c109
1 files changed, 94 insertions, 15 deletions
diff --git a/usr/src/lib/nsswitch/ldap/common/getgrent.c b/usr/src/lib/nsswitch/ldap/common/getgrent.c
index bfcec21fbb..2682e6e2f8 100644
--- a/usr/src/lib/nsswitch/ldap/common/getgrent.c
+++ b/usr/src/lib/nsswitch/ldap/common/getgrent.c
@@ -25,6 +25,7 @@
#include <grp.h>
#include "ldap_common.h"
+#include <string.h>
/* String which may need to be removed from beginning of group password */
#define _CRYPT "{CRYPT}"
@@ -40,8 +41,21 @@
#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))"
-#define _F_GETGRMEM_SSD "(&(%%s)(memberUid=%s))"
+/*
+ * Group membership can be defined by either username or DN, so when searching
+ * for groups by member we need to consider both. The first parameter in the
+ * filter is replaced by username, the second by DN.
+ */
+#define _F_GETGRMEM \
+ "(&(objectClass=posixGroup)(|(memberUid=%s)(memberUid=%s)))"
+#define _F_GETGRMEM_SSD "(&(%%s)(|(memberUid=%s)(memberUid=%s)))"
+
+/*
+ * Copied from getpwnam.c, needed to look up user DN.
+ * Would it be better to move to ldap_common.h rather than duplicate?
+ */
+#define _F_GETPWNAM "(&(objectClass=posixAccount)(uid=%s))"
+#define _F_GETPWNAM_SSD "(&(%%s)(uid=%s))"
static const char *gr_attrs[] = {
_G_NAME,
@@ -75,6 +89,7 @@ _nss_ldap_group2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
char **gname, **passwd, **gid, *password, *end;
char gid_nobody[NOBODY_STR_LEN];
char *gid_nobody_v[1];
+ char *member_str, *strtok_state;
ns_ldap_attr_t *members;
(void) snprintf(gid_nobody, sizeof (gid_nobody), "%u", GID_NOBODY);
@@ -140,15 +155,34 @@ _nss_ldap_group2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
nss_result = NSS_STR_PARSE_PARSE;
goto result_grp2str;
}
- if (firstime) {
- len = snprintf(buffer, buflen, "%s",
- members->attrvalue[i]);
- TEST_AND_ADJUST(len, buffer, buflen, result_grp2str);
- firstime = 0;
+ /*
+ * If we find an '=' in the member attribute value, treat it as
+ * a DN, otherwise as a username.
+ */
+ if (member_str = strchr(members->attrvalue[i], '=')) {
+ member_str++; /* skip over the '=' */
+ /* Fail if we can't pull a username out of the RDN */
+ if (! (member_str = strtok_r(member_str,
+ ",", &strtok_state))) {
+ nss_result = NSS_STR_PARSE_PARSE;
+ goto result_grp2str;
+ }
} else {
- len = snprintf(buffer, buflen, ",%s",
- members->attrvalue[i]);
- TEST_AND_ADJUST(len, buffer, buflen, result_grp2str);
+ member_str = members->attrvalue[i];
+ }
+ if (*member_str != '\0') {
+ if (firstime) {
+ len = snprintf(buffer, buflen, "%s",
+ member_str);
+ TEST_AND_ADJUST(len, buffer, buflen,
+ result_grp2str);
+ firstime = 0;
+ } else {
+ len = snprintf(buffer, buflen, ",%s",
+ member_str);
+ TEST_AND_ADJUST(len, buffer, buflen,
+ result_grp2str);
+ }
}
}
nomember:
@@ -250,7 +284,8 @@ getbymember(ldap_backend_ptr be, void *a)
{
int i, j, k;
int gcnt = (int)0;
- char **groupvalue, **membervalue;
+ char **groupvalue, **membervalue, *member_str;
+ char *strtok_state;
nss_status_t lstat;
struct nss_groupsbymem *argp = (struct nss_groupsbymem *)a;
char searchfilter[SEARCHFILTERLEN];
@@ -258,7 +293,7 @@ getbymember(ldap_backend_ptr be, void *a)
char name[SEARCHFILTERLEN];
ns_ldap_result_t *result;
ns_ldap_entry_t *curEntry;
- char *username;
+ char *username, **dn_attr, *dn;
gid_t gid;
int ret;
@@ -269,14 +304,45 @@ getbymember(ldap_backend_ptr be, void *a)
if (_ldap_filter_name(name, argp->username, sizeof (name)) != 0)
return ((nss_status_t)NSS_NOTFOUND);
- ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETGRMEM, name);
+ ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETPWNAM, name);
+ if (ret >= sizeof (searchfilter) || ret < 0)
+ return ((nss_status_t)NSS_NOTFOUND);
+
+ ret = snprintf(userdata, sizeof (userdata), _F_GETPWNAM_SSD, name);
+ if (ret >= sizeof (userdata) || ret < 0)
+ return ((nss_status_t)NSS_NOTFOUND);
+
+ /*
+ * Look up the user DN in ldap. If it's not found, search solely by
+ * username.
+ */
+ lstat = (nss_status_t)_nss_ldap_nocb_lookup(be, NULL,
+ _PASSWD, searchfilter, NULL, _merge_SSD_filter, userdata);
+ if (lstat != (nss_status_t)NS_LDAP_SUCCESS)
+ return ((nss_status_t)lstat);
+
+ if (be->result == NULL ||
+ !(dn_attr = __ns_ldap_getAttr(be->result->entry, "dn")))
+ dn = name;
+ else
+ dn = dn_attr[0];
+
+ ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETGRMEM, name,
+ dn);
if (ret >= sizeof (searchfilter) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
- ret = snprintf(userdata, sizeof (userdata), _F_GETGRMEM_SSD, name);
+ ret = snprintf(userdata, sizeof (userdata), _F_GETGRMEM_SSD, name,
+ dn);
if (ret >= sizeof (userdata) || ret < 0)
return ((nss_status_t)NSS_NOTFOUND);
+ /*
+ * Free up resources from user DN search before performing group
+ * search.
+ */
+ (void) __ns_ldap_freeResult((ns_ldap_result_t **)&be->result);
+
gcnt = (int)argp->numgids;
lstat = (nss_status_t)_nss_ldap_nocb_lookup(be, NULL,
_GROUP, searchfilter, NULL, _merge_SSD_filter, userdata);
@@ -291,7 +357,20 @@ getbymember(ldap_backend_ptr be, void *a)
membervalue = __ns_ldap_getAttr(curEntry, "memberUid");
if (membervalue) {
for (j = 0; membervalue[j]; j++) {
- if (strcmp(membervalue[j], username) == NULL) {
+ /*
+ * If we find an '=' in the member attribute
+ * value, treat it as a DN, otherwise as a
+ * username.
+ */
+ if (member_str = strchr(membervalue[j], '=')) {
+ member_str++; /* skip over the '=' */
+ member_str = strtok_r(member_str, ",",
+ &strtok_state);
+ } else {
+ member_str = membervalue[j];
+ }
+ if (member_str &&
+ strcmp(member_str, username) == NULL) {
groupvalue = __ns_ldap_getAttr(curEntry,
"gidnumber");
gid = (gid_t)strtol(groupvalue[0],