1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * CDDL HEADER START
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * The contents of this file are subject to the terms of the
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Common Development and Distribution License (the "License").
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * You may not use this file except in compliance with the License.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * See the License for the specific language governing permissions
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * and limitations under the License.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * When distributing Covered Code, include this CDDL HEADER in each
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * If applicable, add the following below this CDDL HEADER, with the
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * fields enclosed by brackets "[]" replaced with your own identifying
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * information: Portions Copyright [yyyy] [name of copyright owner]
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * CDDL HEADER END
cb174861876aea6950a7ab4ce944aff84b1914cdjoyce mcintosh * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Retrieve directory information for Active Directory users.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Information required by the function that handles the callback from LDAP
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * when responses are received.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brownstatic void directory_provider_ad_cb(LDAP *ld, LDAPMessage **ldapres, int rc,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brownstatic void directory_provider_ad_cb1(LDAP *ld, LDAPMessage *msg,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brownstatic directory_error_t bv_list_dav(directory_values_rpc *lvals,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brownstatic directory_error_t directory_provider_ad_lookup(
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown directory_entry_rpc *pent, const char * const * attrs, int nattrs,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brownstatic directory_error_t get_domain(LDAP *ld, LDAPMessage *ldapres,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brownstatic directory_error_t directory_provider_ad_utils_error(char *func, int rc);
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brownstatic void dump_bv_list(const char *attr, struct berval **bv);
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Add an entry to a NULL-terminated list, if it's not already there.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Assumes that the list has been allocated large enough for all additions,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * and prefilled with NULL.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brownmaybe_add_to_list(const char **list, const char *s)
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Copy a counted attribute list to a NULL-terminated one.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * In the process, examine the requested attributes and augment
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * the list as required to support any synthesized attributes
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * requested.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brownconst char **
1fcced4c370617db71610fecffd5451a5894ca5eJordan Browncopy_and_augment_attr_list(char **req_list, int req_list_len)
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown calloc(req_list_len + MAX_EXTRA_ATTRS + 1, sizeof (*new_list));
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown (void) memcpy(new_list, req_list, req_list_len * sizeof (char *));
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown for (i = 0; i < req_list_len; i++) {
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown const char *a = req_list[i];
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Note that you must update MAX_EXTRA_ATTRS above if you
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * add to this list.
cb174861876aea6950a7ab4ce944aff84b1914cdjoyce mcintosh if (uu_strcaseeq(a, "x-sun-canonicalName")) {
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown /* None needed for x-sun-provider */
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Retrieve information by name.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Called indirectly through the Directory_provider_static structure.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * If we don't have any AD servers handy, we can't find anything.
b3700b074e637f8c6991b70754c88a2cfffb246bGordon Ross * XXX: this should be using our DC, not the GC.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown /* 6835280 spurious lint error if the strlen is in the declaration */
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown int len = strlen(_idmapdstate.cfg->pgcfg.default_domain);
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown (void) strcpy(default_domain, _idmapdstate.cfg->pgcfg.default_domain);
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Turn our counted-array argument into a NULL-terminated array.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * At the same time, add in any attributes that we need to support
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * any requested synthesized attributes.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown attrs2 = copy_and_augment_attr_list(attrs->idmap_utf8str_list_val,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown for (i = 0; i < ids->idmap_utf8str_list_len; i++) {
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Extract the type for this particular ID.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Advance to the next type, if it's there, else keep
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * using this type until we run out of IDs.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * If this entry has already been handled, one way or another,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Allow for expanding every character to \xx, plus some
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * space for the query syntax.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Mildly surprisingly, AD appears to allow searching
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * based on text SIDs. Must be a special case on the
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * server end.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown de = directory_provider_ad_lookup(&del[i], attrs2,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Try samAccountName.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Note that here we rely on checking the returned
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * distinguishedName to make sure that we found an
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * entry from the right domain, because there's no
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * attribute we can straightforwardly filter for to
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * match domain.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Eventually we should perhaps also try
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * userPrincipalName.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown "(&(samAccountName=%v1)(objectClass=%v3))",
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown de = directory_provider_ad_lookup(&del[i], attrs2,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Note that attrs is NULL terminated, and that nattrs is the number
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * of attributes requested by the user... which might be fewer than are
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * in attrs because of attributes that we need for our own processing.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown const char * const * attrs,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * NEEDSWORK: Should eventually handle other forests.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * NEEDSWORK: Should eventually handle non-GC attributes.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown /* Stash away information for the callback function. */
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown rc = adutils_lookup_batch_start(ad, 1, directory_provider_ad_cb,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown rc = adutils_lookup_batch_add(qs, filter, attrs, domain,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * NEEDSWORK: We're consistently getting -9997 here.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * What does it mean?
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Callback from the LDAP functions when they get responses.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * We don't really need (nor want) asynchronous handling, but it's
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * what libadutils gives us.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Process a single entry returned by an LDAP callback.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Note that this performs a function roughly equivalent to the
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * directory*Populate() functions in the other providers.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Given an LDAP response, populate the directory entry for return to
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * the caller. This one differs primarily in that we're working directly
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * with LDAP, so we don't have to do any attribute translation.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * We don't have a way to filter for entries from the right domain
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * in the LDAP query, so we check for it here. Searches based on
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * samAccountName might yield results from the wrong domain.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown if (cbinfo->domain != NULL && !domain_eq(cbinfo->domain, domain))
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * If we've already found a match, error.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown llvals = calloc(nattrs, sizeof (directory_values_rpc));
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown pent->directory_entry_rpc_u.attrs.attrs_val = llvals;
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown pent->directory_entry_rpc_u.attrs.attrs_len = nattrs;
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown for (i = 0; i < nattrs; i++) {
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown const char *a = attrs[i];
cb174861876aea6950a7ab4ce944aff84b1914cdjoyce mcintosh } else if (uu_strcaseeq(a, "x-sun-canonicalName")) {
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown bv = ldap_get_values_len(ld, msg, "sAMAccountName");
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown if (n > 0) {
cb174861876aea6950a7ab4ce944aff84b1914cdjoyce mcintosh } else if (uu_strcaseeq(a, "x-sun-provider")) {
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown "No memory allocating return value for user lookup", NULL);
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Given a struct berval, populate a directory attribute value (which is a
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * list of values).
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Note that here we populate the DAV with the exact bytes that LDAP returns.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Back over in the client it appends a \0 so that strings are null
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * terminated.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brownbv_list_dav(directory_values_rpc *lvals, struct berval **bv)
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown lvals->directory_values_rpc_u.values.values_val = dav;
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown lvals->directory_values_rpc_u.values.values_len = n;
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown for (i = 0; i < n; i++) {
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown dav[i].directory_value_rpc_len = bv[i]->bv_len;
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown "Insufficient memory copying values"));
1fcced4c370617db71610fecffd5451a5894ca5eJordan Browndump_bv_list(const char *attr, struct berval **bv)
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown dump(stderr, " ", bv[i]->bv_val, bv[i]->bv_len);
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown#endif /* DUMP_VALUES */
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Return the domain associated with the specified entry.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown return directory_error("AD.get_domain.ldap_get_dn",
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown "ldap_get_dn: %1 (%2)\n"
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown "matched: %3\n"
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown "error: %4",
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown de = directory_error("Unknown.get_domain.adutils_dn2dns",
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown "get_domain: Unexpected error from adutils_dn2dns(%1)",
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown * Given an error report from libadutils, generate a directory_error_t.
1fcced4c370617db71610fecffd5451a5894ca5eJordan Browndirectory_provider_ad_utils_error(char *func, int rc)
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown (void) snprintf(rcstr, sizeof (rcstr), "%d", rc);
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown (void) snprintf(code, sizeof (code), "ADUTILS.%d", rc);
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown "Error %2 from adutils function %1", func, rcstr, NULL));