Print this page
12236 getmembers_DN doesn't properly handle errors from __ns_ldap_dn2uid
12240 nss_ldap does not properly look up group members by distinguished name
@@ -19,10 +19,11 @@
* CDDL HEADER END
*/
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2017 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2020 Joyent, Inc.
*/
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
@@ -3593,107 +3594,176 @@
;
__ns_ldap_list_batch_release(batch);
return (rc);
}
+typedef struct lookup_data {
+ const char *lkd_dn;
+ const char *lkd_service;
+ const char *lkd_filter;
+ const ns_cred_t *lkd_cred;
+ ns_conn_user_t *lkd_user;
+} lookup_data_t;
+
/*
- * find_domainname performs one or more LDAP searches to
- * find the value of the nisdomain attribute associated with
- * the input DN (with no retry).
+ * This creates a service search descriptor that can be used to
+ * retrieve a specific DN by using the DN as the basedn with a search
+ * scope of 'base'. We don't use any service SSDs in this instance since
+ * they are intended to search specific locations/subtrees and filter the
+ * results, while here we are wanting to retrieve a specific entry.
*/
-
static int
-find_domainname(const char *dn, char **domainname, const ns_cred_t *cred,
- ns_ldap_error_t **errorp, ns_conn_user_t *conn_user)
+lookup_create_ssd(lookup_data_t *dn_data, ns_ldap_search_desc_t **descpp)
{
+ ns_ldap_search_desc_t *dptr;
+ *descpp = NULL;
+
+ dptr = calloc(1, sizeof (ns_ldap_search_desc_t));
+ if (dptr == NULL)
+ return (NS_LDAP_MEMORY);
+
+ dptr->basedn = strdup(dn_data->lkd_dn);
+ dptr->scope = NS_LDAP_SCOPE_BASE;
+ dptr->filter = strdup(UIDFILTER);
+
+ if (dptr->basedn == NULL || dptr->filter == NULL) {
+ __ns_ldap_freeASearchDesc(dptr);
+ return (NS_LDAP_MEMORY);
+ }
+
+ *descpp = dptr;
+ return (NS_LDAP_SUCCESS);
+}
+
+static int
+lookup_dn(lookup_data_t *dn_data, const char **attrs,
+ ns_ldap_result_t **resultp, ns_ldap_error_t **errorp)
+{
ns_ldap_cookie_t *cookie;
- ns_ldap_search_desc_t **sdlist;
- ns_ldap_search_desc_t *dptr;
- int rc;
- char **value;
+ int rc = 0;
int flags = 0;
- *domainname = NULL;
*errorp = NULL;
+ *resultp = NULL;
- /* Initialize State machine cookie */
+ if (dn_data == NULL || dn_data->lkd_dn == NULL ||
+ dn_data->lkd_dn[0] == '\0' || dn_data->lkd_filter == NULL)
+ return (NS_LDAP_INVALID_PARAM);
+
cookie = init_search_state_machine();
- if (cookie == NULL) {
+ if (cookie == NULL)
return (NS_LDAP_MEMORY);
- }
- cookie->conn_user = conn_user;
- /* see if need to follow referrals */
- rc = __s_api_toFollowReferrals(flags,
- &cookie->followRef, errorp);
- if (rc != NS_LDAP_SUCCESS) {
- delete_search_cookie(cookie);
- return (rc);
+ rc = __s_api_toFollowReferrals(flags, &cookie->followRef, errorp);
+ if (rc != NS_LDAP_SUCCESS)
+ goto out;
+
+ /* 1 for SSD, 1 for terminating NULL */
+ cookie->sdlist = calloc(2, sizeof (ns_ldap_search_desc_t *));
+ if (cookie->sdlist == NULL) {
+ rc = NS_LDAP_MEMORY;
+ goto out;
}
- /* Create default service Desc */
- sdlist = (ns_ldap_search_desc_t **)calloc(2,
- sizeof (ns_ldap_search_desc_t *));
- if (sdlist == NULL) {
- delete_search_cookie(cookie);
- cookie = NULL;
- return (NS_LDAP_MEMORY);
+ rc = lookup_create_ssd(dn_data, &cookie->sdlist[0]);
+ if (rc != NS_LDAP_SUCCESS)
+ goto out;
+
+ if (dn_data->lkd_service != NULL) {
+ /*
+ * If a service was specified, set that on the cookie so
+ * that search_state_machine() will properly map
+ * attributes and objectclasses.
+ */
+ cookie->service = strdup(dn_data->lkd_service);
+ if (cookie->service == NULL) {
+ rc = NS_LDAP_MEMORY;
+ goto out;
}
- dptr = (ns_ldap_search_desc_t *)
- calloc(1, sizeof (ns_ldap_search_desc_t));
- if (dptr == NULL) {
- free(sdlist);
- delete_search_cookie(cookie);
- cookie = NULL;
- return (NS_LDAP_MEMORY);
}
- sdlist[0] = dptr;
- /* search base is dn */
- dptr->basedn = strdup(dn);
-
- /* search scope is base */
- dptr->scope = NS_LDAP_SCOPE_BASE;
-
- /* search filter is "nisdomain=*" */
- dptr->filter = strdup(_NIS_FILTER);
-
- cookie->sdlist = sdlist;
- cookie->i_filter = strdup(dptr->filter);
- cookie->i_attr = nis_domain_attrs;
- cookie->i_auth = cred;
+ cookie->i_attr = attrs;
+ cookie->i_auth = dn_data->lkd_cred;
cookie->i_flags = 0;
+ cookie->i_filter = strdup(dn_data->lkd_filter);
+ if (cookie->i_filter == NULL) {
+ rc = NS_LDAP_MEMORY;
+ goto out;
+ }
- /* Process search */
- rc = search_state_machine(cookie, INIT, 0);
-
- /* Copy domain name if found */
+ /*
+ * Actually perform the search. The return value is only used when
+ * iterating through multiple results. Since we are searching with
+ * a scope of base, we will always get at most one result entry,
+ * we ignore the return value and look at err_rc to determine if
+ * there were any errors.
+ */
+ (void) search_state_machine(cookie, INIT, 0);
rc = cookie->err_rc;
+
if (rc != NS_LDAP_SUCCESS) {
- if (conn_user != NULL && conn_user->ns_error != NULL) {
- *errorp = conn_user->ns_error;
- conn_user->ns_error = NULL;
+ ns_conn_user_t *user = dn_data->lkd_user;
+
+ if (user != NULL && user->ns_error != NULL) {
+ *errorp = user->ns_error;
+ user->ns_error = NULL;
} else {
*errorp = cookie->errorp;
+ cookie->errorp = NULL;
}
- }
- if (cookie->result == NULL)
+ } else if (cookie->result != NULL) {
+ *resultp = cookie->result;
+ cookie->result = NULL;
+ } else {
rc = NS_LDAP_NOTFOUND;
- if (rc == NS_LDAP_SUCCESS) {
- value = __ns_ldap_getAttr(cookie->result->entry,
- _NIS_DOMAIN);
- if (value[0])
+ }
+
+out:
+ delete_search_cookie(cookie);
+ return (rc);
+}
+
+/*
+ * find_domainname performs one or more LDAP searches to
+ * find the value of the nisdomain attribute associated with
+ * the input DN (with no retry).
+ */
+
+static int
+find_domainname(const char *dn, char **domainname, const ns_cred_t *cred,
+ ns_ldap_error_t **errorp, ns_conn_user_t *conn_user)
+{
+ lookup_data_t ldata;
+ ns_ldap_result_t *result;
+ char **value;
+ int rc;
+
+ *domainname = NULL;
+ *errorp = NULL;
+
+ ldata.lkd_dn = dn;
+ ldata.lkd_service = NULL;
+ ldata.lkd_filter = _NIS_FILTER;
+ ldata.lkd_cred = cred;
+ ldata.lkd_user = conn_user;
+
+ rc = lookup_dn(&ldata, nis_domain_attrs, &result, errorp);
+ if (rc != NS_LDAP_SUCCESS)
+ return (rc);
+
+ value = __ns_ldap_getAttr(result->entry, _NIS_DOMAIN);
+
+ if (value != NULL && value[0] != NULL) {
*domainname = strdup(value[0]);
- else
+ if (*domainname == NULL)
+ rc = NS_LDAP_MEMORY;
+ } else {
rc = NS_LDAP_NOTFOUND;
}
- if (cookie->result != NULL)
- (void) __ns_ldap_freeResult(&cookie->result);
- cookie->errorp = NULL;
- delete_search_cookie(cookie);
- cookie = NULL;
+
+ (void) __ns_ldap_freeResult(&result);
return (rc);
}
/*
* __s_api_find_domainname performs one or more LDAP searches to
@@ -4237,77 +4307,55 @@
_P_UID,
(char *)NULL
};
int
-__ns_ldap_dn2uid(const char *dn, char **userID, const ns_cred_t *cred,
+__ns_ldap_dn2uid(const char *dn, char **userIDp, const ns_cred_t *cred,
ns_ldap_error_t **errorp)
{
- ns_ldap_result_t *result = NULL;
- char *filter, *userdata;
- char errstr[MAXERROR];
+ lookup_data_t ldata;
+ ns_ldap_result_t *result;
char **value;
- int rc = 0;
- size_t len;
+ int rc;
*errorp = NULL;
- *userID = NULL;
+ *userIDp = NULL;
if ((dn == NULL) || (dn[0] == '\0'))
return (NS_LDAP_INVALID_PARAM);
- len = strlen(UIDDNFILTER) + strlen(dn) + 1;
- filter = malloc(len);
- if (filter == NULL) {
- return (NS_LDAP_MEMORY);
- }
- (void) snprintf(filter, len, UIDDNFILTER, dn);
+ /*
+ * Many LDAP servers do not support using the dn in a search
+ * filter. As a result, we unfortunately cannot use __ns_ldap_list()
+ * to lookup the DN. Instead we perform a search with the baseDN
+ * being the DN we are looking for with a scope of 'base' to
+ * return the entry, as this should be supported by all LDAP servers.
+ */
+ ldata.lkd_dn = dn;
- len = strlen(UIDDNFILTER_SSD) + strlen(dn) + 1;
- userdata = malloc(len);
- if (userdata == NULL) {
- free(filter);
- return (NS_LDAP_MEMORY);
- }
- (void) snprintf(userdata, len, UIDDNFILTER_SSD, dn);
-
/*
- * Unlike uid2dn, we DO want attribute mapping, so that
- * "uid" is mapped to/from samAccountName, for example.
+ * Since we are looking up a user account by its DN, use the attribute
+ * and objectclass mappings (if present) for the passwd service.
*/
- rc = __ns_ldap_list("passwd", filter,
- __s_api_merge_SSD_filter,
- dn2uid_attrs, cred, 0,
- &result, errorp, NULL,
- userdata);
- free(filter);
- filter = NULL;
- free(userdata);
- userdata = NULL;
+ ldata.lkd_service = "passwd";
+ ldata.lkd_filter = UIDDNFILTER;
+ ldata.lkd_cred = cred;
+ ldata.lkd_user = NULL;
+
+ rc = lookup_dn(&ldata, dn2uid_attrs, &result, errorp);
if (rc != NS_LDAP_SUCCESS)
- goto out;
+ return (rc);
- if (result->entries_count > 1) {
- (void) sprintf(errstr,
- gettext("Too many entries are returned for %s"), dn);
- MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
- NS_LDAP_MEMORY);
- rc = NS_LDAP_INTERNAL;
- goto out;
- }
-
value = __ns_ldap_getAttr(result->entry, _P_UID);
- if (value == NULL || value[0] == NULL) {
+ if (value != NULL && value[0] != NULL) {
+ *userIDp = strdup(value[0]);
+ if (*userIDp == NULL)
+ rc = NS_LDAP_MEMORY;
+ } else {
rc = NS_LDAP_NOTFOUND;
- goto out;
}
- *userID = strdup(value[0]);
- rc = NS_LDAP_SUCCESS;
-
-out:
(void) __ns_ldap_freeResult(&result);
- result = NULL;
return (rc);
}
int
__ns_ldap_host2dn(const char *host, const char *domain, char **hostDN,