2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <sys/types.h>
2N/A#include <stdlib.h>
2N/A#include <libintl.h>
2N/A#include <ctype.h>
2N/A#include <syslog.h>
2N/A#include <sys/stat.h>
2N/A#include <fcntl.h>
2N/A#include <unistd.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <priv.h>
2N/A#include <ldif.h>
2N/A
2N/A#include "ns_sldap.h"
2N/A#include "ns_internal.h"
2N/A#include "ns_cache_door.h"
2N/A#include "ns_connmgmt.h"
2N/A
2N/A#define _NIS_FILTER "nisdomain=*"
2N/A#define _NIS_DOMAIN "nisdomain"
2N/Astatic const char *nis_domain_attrs[] = {
2N/A _NIS_DOMAIN,
2N/A (char *)NULL
2N/A};
2N/A
2N/A/*
2N/A * The following are from libldap. Used to check if an attribute value
2N/A * should be base64-encoded when displayed by tools such as ldaplist.
2N/A */
2N/A#define LDIF_SAFE_CHAR(c) ((c) != '\r' && (c) != '\n')
2N/A#define LDIF_CONSERVATIVE_CHAR(c) (LDIF_SAFE_CHAR(c) && isascii((c)) && \
2N/A (isprint((c)) || (c) == '\t'))
2N/A
2N/A
2N/Astatic int validate_filter(ns_ldap_cookie_t *cookie);
2N/Astatic char *__s_api_remove_rdn_space(char *rdn);
2N/A
2N/Avoid
2N/A__ns_ldap_freeEntry(ns_ldap_entry_t *ep)
2N/A{
2N/A int j, k = 0;
2N/A
2N/A if (ep == NULL)
2N/A return;
2N/A
2N/A if (ep->attr_pair == NULL) {
2N/A free(ep);
2N/A return;
2N/A }
2N/A for (j = 0; j < ep->attr_count; j++) {
2N/A if (ep->attr_pair[j] == NULL)
2N/A continue;
2N/A if (ep->attr_pair[j]->attrname)
2N/A free(ep->attr_pair[j]->attrname);
2N/A if (ep->attr_pair[j]->attrvalue) {
2N/A for (k = 0; (k < ep->attr_pair[j]->value_count) &&
2N/A (ep->attr_pair[j]->attrvalue[k]); k++) {
2N/A free(ep->attr_pair[j]->attrvalue[k]);
2N/A }
2N/A free(ep->attr_pair[j]->attrvalue);
2N/A }
2N/A free(ep->attr_pair[j]);
2N/A }
2N/A free(ep->attr_pair);
2N/A free(ep);
2N/A}
2N/A
2N/Astatic void
2N/A_freeControlList(LDAPControl ***ctrls)
2N/A{
2N/A LDAPControl **ctrl;
2N/A
2N/A if (ctrls == NULL || *ctrls == NULL)
2N/A return;
2N/A
2N/A for (ctrl = *ctrls; *ctrl != NULL; ctrl++)
2N/A ldap_control_free(*ctrl);
2N/A free(*ctrls);
2N/A *ctrls = NULL;
2N/A}
2N/A/*
2N/A * If requested, convert attribute type in a RDN that has an attribute
2N/A * mapping to the original mappped type. Either way, the DN will be
2N/A * normalized (i.e., remove unnecessary spaces).
2N/A *
2N/A * For example:
2N/A *
2N/A * e.g.
2N/A * cn<->cn-st and iphostnumber<->iphostnumber-st
2N/A * cn-st= aaa + iphostnumber-st= 10.10.01.01
2N/A * is mapped to
2N/A * cn=aaa+iphostnumber=10.10.01.01
2N/A *
2N/A * Input - service: e.g. hosts, passwd etc.
2N/A * rdn: RDN
2N/A * map_attr: if TRUE, map attribute
2N/A * Return: NULL - No attribute mapping in the RDN
2N/A * Non-NULL - The attribute type(s) in the RDN are mapped and
2N/A * the memory is allocated for the new rdn.
2N/A *
2N/A */
2N/Astatic char *
2N/A_cvtRDN(const char *service, const char *rdn, boolean_t map_attr)
2N/A{
2N/A char **attrs, **mapped_attrs, *type, *value, *attr;
2N/A char **mapp = NULL;
2N/A char *new_rdn = NULL;
2N/A int nAttr = 0, i, attr_mapped, len = 0;
2N/A
2N/A /* Break down "type = value\0" pairs. */
2N/A if ((attrs = ldap_explode_rdn(rdn, 0)) == NULL)
2N/A return (NULL);
2N/A
2N/A for (nAttr = 0; attrs[nAttr] != NULL; nAttr++) {
2N/A /* remove leading/trailing and those spaces around '=' */
2N/A attrs[nAttr] = __s_api_remove_rdn_space(attrs[nAttr]);
2N/A }
2N/A
2N/A if ((mapped_attrs = (char **)calloc(nAttr, sizeof (char *))) == NULL) {
2N/A ldap_value_free(attrs);
2N/A return (NULL);
2N/A }
2N/A
2N/A attr_mapped = 0;
2N/A for (i = 0; i < nAttr; i++) {
2N/A /* Parse type=value pair */
2N/A if ((type = strtok_r(attrs[i], "=", &value)) == NULL ||
2N/A value == NULL)
2N/A goto cleanup;
2N/A /* Reverse map: e.g. cn-sm -> cn */
2N/A if (map_attr && (mapp =
2N/A __ns_ldap_getOrigAttribute(service, type)) != NULL &&
2N/A mapp[0] != NULL) {
2N/A /* The attribute mapping is found */
2N/A type = mapp[0];
2N/A attr_mapped = 1;
2N/A
2N/A /* "type=value\0" */
2N/A len = strlen(type) + strlen(value) + 2;
2N/A
2N/A /* Reconstruct type=value pair. A string is allocated */
2N/A if ((attr = (char *)calloc(1, len)) == NULL) {
2N/A __s_api_free2dArray(mapp);
2N/A goto cleanup;
2N/A }
2N/A (void) snprintf(attr, len, "%s=%s", type, value);
2N/A mapped_attrs[i] = attr;
2N/A } else {
2N/A /*
2N/A * No attribute mapping. attrs[i] is going to be copied
2N/A * later. Restore "type\0value\0" back to
2N/A * "type=value\0".
2N/A */
2N/A type[strlen(type)] = '=';
2N/A }
2N/A __s_api_free2dArray(mapp);
2N/A }
2N/A
2N/A len = 0;
2N/A /* Reconstruct RDN from type=value pairs */
2N/A for (i = 0; i < nAttr; i++) {
2N/A if (mapped_attrs[i])
2N/A len += strlen(mapped_attrs[i]);
2N/A else
2N/A len += strlen(attrs[i]);
2N/A /* Add 1 for "+" */
2N/A len++;
2N/A }
2N/A if ((new_rdn = (char *)calloc(1, ++len)) == NULL)
2N/A goto cleanup;
2N/A for (i = 0; i < nAttr; i++) {
2N/A if (i > 0)
2N/A /* Add separator */
2N/A (void) strlcat(new_rdn, "+", len);
2N/A
2N/A if (mapped_attrs[i])
2N/A (void) strlcat(new_rdn, mapped_attrs[i], len);
2N/A else
2N/A (void) strlcat(new_rdn, attrs[i], len);
2N/A
2N/A }
2N/Acleanup:
2N/A ldap_value_free(attrs);
2N/A if (mapped_attrs) {
2N/A if (attr_mapped) {
2N/A for (i = 0; i < nAttr; i++) {
2N/A if (mapped_attrs[i])
2N/A free(mapped_attrs[i]);
2N/A }
2N/A }
2N/A free(mapped_attrs);
2N/A }
2N/A
2N/A return (new_rdn);
2N/A}
2N/A
2N/A/*
2N/A * If requested, convert attribute type in a DN that has an attribute
2N/A * mapping to the original mappped type. Either way, the DN will be
2N/A * normalized (i.e., remove unnecessary spaces).
2N/A *
2N/A * For example:
2N/A *
2N/A * The mappings are cn<->cn-sm, iphostnumber<->iphostnumber-sm
2N/A * dn: cn-sm=aaa + iphostnumber-sm= 9.9.9.9,dc=central,dc=sun,dc=com
2N/A * is converted to
2N/A * dn: cn=aaa+iphostnumber=9.9.9.9,dc=central,dc=sun,dc=com
2N/A *
2N/A * Input - service: e.g. hosts, passwd etc.
2N/A * dn: the value of a distinguished name
2N/A * map_attr: if TRUE, map attribute
2N/A * Return - NULL: error
2N/A * non-NULL: A converted DN and the memory is allocated
2N/A */
2N/Astatic char *
2N/A_cvtDN(const char *service, const char *dn, boolean_t map_attr)
2N/A{
2N/A char **mapped_rdns;
2N/A char **rdns, *new_rdn, *new_dn = NULL;
2N/A int nRdn = 0, i, len = 0;
2N/A boolean_t rdn_mapped;
2N/A
2N/A if (dn == NULL)
2N/A return (NULL);
2N/A
2N/A /* Attribute mapping requires 'service' */
2N/A if (map_attr) {
2N/A if (service == NULL)
2N/A return (NULL);
2N/A } else {
2N/A /* attribute mapping not needed and no space in DN, done */
2N/A if (strchr(dn, SPACETOK) == NULL)
2N/A return (strdup(dn));
2N/A }
2N/A
2N/A if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
2N/A return (NULL);
2N/A
2N/A for (nRdn = 0; rdns[nRdn] != NULL; nRdn++)
2N/A continue;
2N/A
2N/A if ((mapped_rdns = (char **)calloc(nRdn, sizeof (char *))) == NULL) {
2N/A ldap_value_free(rdns);
2N/A return (NULL);
2N/A }
2N/A
2N/A rdn_mapped = B_FALSE;
2N/A /* Break down RDNs in a DN */
2N/A for (i = 0; i < nRdn; i++) {
2N/A if ((new_rdn = _cvtRDN(service, rdns[i], map_attr)) != NULL) {
2N/A mapped_rdns[i] = new_rdn;
2N/A rdn_mapped = B_TRUE;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Reconstruct dn from RDNs.
2N/A * Calculate the length first.
2N/A */
2N/A for (i = 0; i < nRdn; i++) {
2N/A if (mapped_rdns[i])
2N/A len += strlen(mapped_rdns[i]);
2N/A else
2N/A len += strlen(rdns[i]);
2N/A
2N/A /* add 1 for ',' */
2N/A len ++;
2N/A }
2N/A if ((new_dn = (char *)calloc(1, ++len)) == NULL)
2N/A goto cleanup;
2N/A for (i = 0; i < nRdn; i++) {
2N/A if (i > 0)
2N/A /* Add separator */
2N/A (void) strlcat(new_dn, ",", len);
2N/A
2N/A if (mapped_rdns[i])
2N/A (void) strlcat(new_dn, mapped_rdns[i], len);
2N/A else
2N/A (void) strlcat(new_dn, rdns[i], len);
2N/A
2N/A }
2N/A
2N/Acleanup:
2N/A ldap_value_free(rdns);
2N/A if (rdn_mapped) {
2N/A for (i = 0; i < nRdn; i++) {
2N/A if (mapped_rdns[i])
2N/A free(mapped_rdns[i]);
2N/A }
2N/A }
2N/A free(mapped_rdns);
2N/A
2N/A return (new_dn);
2N/A}
2N/A
2N/A/*
2N/A * Checks which ones of the internal operational attributes
2N/A * (cookie->i_extra_info_attr) are requested and returns
2N/A * the values. Currently only NS_LDAP_OP_ATTR_SERVER_TYPE
2N/A * is supported.
2N/A */
2N/Avoid
2N/Aset_extra_info(ns_ldap_cookie_t *cookie)
2N/A{
2N/A const char * const * iattr;
2N/A int i;
2N/A int attr_cnt = 0;
2N/A ns_ldap_entry_t *ep;
2N/A ns_ldap_attr_t **apair;
2N/A
2N/A iattr = cookie->i_extra_info_attr;
2N/A ep = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t));
2N/A if (ep == NULL)
2N/A return;
2N/A
2N/A while (*iattr != NULL) {
2N/A attr_cnt++;
2N/A iattr++;
2N/A }
2N/A
2N/A apair = (ns_ldap_attr_t **)calloc(attr_cnt, sizeof (ns_ldap_attr_t *));
2N/A if (apair == NULL) {
2N/A free(ep);
2N/A return;
2N/A }
2N/A ep->attr_pair = apair;
2N/A
2N/A i = 0;
2N/A for (iattr = cookie->i_extra_info_attr; *iattr != NULL; iattr++) {
2N/A char *val = NS_LDAP_ATTR_VAL_SERVER_UNKNOWN;
2N/A if (strcmp(*iattr, NS_LDAP_OP_ATTR_SERVER_TYPE) == 0) {
2N/A if (cookie->conn == NULL)
2N/A continue;
2N/A switch (cookie->conn->serverType) {
2N/A case NS_LDAP_SERVERTYPE_ODSEE:
2N/A val = NS_LDAP_ATTR_VAL_SERVER_ODSEE;
2N/A break;
2N/A case NS_LDAP_SERVERTYPE_AD:
2N/A val = NS_LDAP_ATTR_VAL_SERVER_AD;
2N/A break;
2N/A case NS_LDAP_SERVERTYPE_OPENLDAP:
2N/A val = NS_LDAP_ATTR_VAL_SERVER_OPENLDAP;
2N/A break;
2N/A case NS_LDAP_SERVERTYPE_OID:
2N/A val = NS_LDAP_ATTR_VAL_SERVER_OID;
2N/A break;
2N/A default:
2N/A val = NS_LDAP_ATTR_VAL_SERVER_UNKNOWN;
2N/A break;
2N/A }
2N/A apair[i] = (ns_ldap_attr_t *)calloc(1,
2N/A sizeof (ns_ldap_attr_t));
2N/A if (apair[i] == NULL) {
2N/A __ns_ldap_freeEntry(ep);
2N/A return;
2N/A }
2N/A
2N/A apair[i]->attrvalue = (char **)calloc(2,
2N/A sizeof (char *));
2N/A if (apair[i]->attrvalue == NULL) {
2N/A __ns_ldap_freeEntry(ep);
2N/A return;
2N/A }
2N/A apair[i]->attrvalue[0] = strdup(val);
2N/A if (apair[i]->attrvalue[0] == NULL) {
2N/A __ns_ldap_freeEntry(ep);
2N/A return;
2N/A }
2N/A apair[i]->attrname =
2N/A strdup(NS_LDAP_OP_ATTR_SERVER_TYPE);
2N/A if (apair[i]->attrname == NULL) {
2N/A __ns_ldap_freeEntry(ep);
2N/A return;
2N/A }
2N/A apair[i]->value_count = 1;
2N/A
2N/A i++;
2N/A }
2N/A }
2N/A
2N/A ep->attr_count = i;
2N/A if (ep->attr_count == 0) {
2N/A __ns_ldap_freeEntry(ep);
2N/A return;
2N/A }
2N/A
2N/A cookie->extra_info = ep;
2N/A}
2N/A
2N/A/*
2N/A * Free the data structure used to track the processing of attributes
2N/A * with range option, such as member.
2N/A */
2N/Astatic void
2N/Afree_range_info(ns_ldap_range_info_t **info)
2N/A{
2N/A ns_ldap_range_attr_t *attr, *next;
2N/A
2N/A if ((*info)->dn != NULL)
2N/A free((*info)->dn);
2N/A if ((*info)->attr_to_search != NULL)
2N/A free((*info)->attr_to_search);
2N/A
2N/A for (attr = (*info)->range_attr; attr != NULL; attr = next) {
2N/A if (attr->mapped_name != NULL)
2N/A free(attr->mapped_name);
2N/A if (attr->attr_and_range != NULL)
2N/A free(attr->attr_and_range);
2N/A next = attr->next;
2N/A free(attr);
2N/A }
2N/A free(*info);
2N/A *info = NULL;
2N/A}
2N/A
2N/A/*
2N/A * Create/add/update the necessary info for the search state
2N/A * machine to collect the next range of the attribute values.
2N/A *
2N/A * 'first' indicates if the attribute range option has
2N/A * just be detected and if the control structure should
2N/A * be created and added to the range_attr list in the
2N/A * range info control structure, *info_p. If it's not
2N/A * TRUE, the control structure will be updated to have
2N/A * the attribute's range value for the next search. Either
2N/A * way, 'attr_type' should always contain the attribute
2N/A * name and the range option specification. The updated
2N/A * attr_and_range string will also have the attribute
2N/A * name and range info together, so that it can be
2N/A * readily used in the attribute list for the next
2N/A * ldap search.
2N/A *
2N/A * See the comments in ns_internal.h for info about
2N/A * ns_ldap_range_attr_t and ns_ldap_range_info_t
2N/A * when used for processing attributes with range
2N/A * options.
2N/A */
2N/Astatic int
2N/Aupdate_range_info(boolean_t first, char *attr_type,
2N/A ns_ldap_range_info_t **info_p)
2N/A{
2N/A ns_ldap_range_attr_t *attr;
2N/A ns_ldap_range_info_t *info;
2N/A int attr_len;
2N/A long next_range_start;
2N/A char *endptr;
2N/A char *attr_end;
2N/A char *last_entry_s;
2N/A char attr_and_range[NS_LDAP_ATTR_AND_RANGE_SIZE];
2N/A boolean_t range_done = B_FALSE;
2N/A
2N/A /*
2N/A * Attribute type with range option has the form:
2N/A * <attr type>;range=n1-n2, where n2 may be '*' (last)
2N/A */
2N/A attr_end = strstr(attr_type, ";range=");
2N/A attr_len = attr_end - attr_type;
2N/A /* get end of range */
2N/A last_entry_s = strchr(attr_end + 7, '-');
2N/A if (last_entry_s == NULL) {
2N/A /* ignore the range setting */
2N/A return (NS_LDAP_SUCCESS);
2N/A }
2N/A
2N/A /*
2N/A * End of range reached and first search result ?
2N/A * No more to be done.
2N/A */
2N/A last_entry_s++;
2N/A if (*last_entry_s == '*') {
2N/A range_done = B_TRUE;
2N/A if (first)
2N/A return (NS_LDAP_SUCCESS);
2N/A } else {
2N/A next_range_start = strtol(last_entry_s, &endptr, 10);
2N/A if (next_range_start == 0 || (*endptr != ';' &&
2N/A *endptr != '\0'))
2N/A /* ignore the range setting */
2N/A return (NS_LDAP_SUCCESS);
2N/A /*
2N/A * generate the "attribute type + option" for the next search:
2N/A * <attr type>;range=start-end
2N/A */
2N/A (void) snprintf(attr_and_range, sizeof (attr_and_range),
2N/A "%.*s;range=%ld-*", attr_len, attr_type,
2N/A next_range_start + 1);
2N/A }
2N/A
2N/A info = *info_p;
2N/A if (info == NULL) {
2N/A *info_p = info = (ns_ldap_range_info_t *)calloc(1,
2N/A sizeof (ns_ldap_range_info_t));
2N/A if (info == NULL)
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A
2N/A if (first) {
2N/A attr = (ns_ldap_range_attr_t *)calloc(1,
2N/A sizeof (ns_ldap_range_attr_t));
2N/A if (attr == NULL) {
2N/A free_range_info(info_p);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A attr->attr_len = attr_len;
2N/A attr->attr_and_range = malloc(NS_LDAP_ATTR_AND_RANGE_SIZE);
2N/A if (attr->attr_and_range == NULL) {
2N/A free_range_info(info_p);
2N/A free(attr);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A
2N/A attr->next = info->range_attr;
2N/A info->range_attr = attr;
2N/A } else {
2N/A for (attr = info->range_attr; attr != NULL; attr = attr->next) {
2N/A if (strncasecmp(attr_type, attr->attr_and_range,
2N/A attr->attr_len + 1) == 0)
2N/A break;
2N/A }
2N/A if (attr == NULL)
2N/A /* ignore this attribute type */
2N/A return (NS_LDAP_SUCCESS);
2N/A
2N/A if (range_done) {
2N/A attr->range_done = B_TRUE;
2N/A return (NS_LDAP_SUCCESS);
2N/A }
2N/A }
2N/A
2N/A (void) strcpy(attr->attr_and_range, attr_and_range);
2N/A
2N/A if (first)
2N/A info->attr_count++;
2N/A
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Take a binary value and return the base64 encoded string.
2N/A * Tag the output string with NS_LDAP_BASE64_TAG, "\1{base64}".
2N/A */
2N/Astatic char *
2N/Ab64_encode(char *value, size_t vlen)
2N/A{
2N/A char *b64s;
2N/A size_t mvlen;
2N/A
2N/A /* Encode 'value', output looks like "\1{base64}:: <encoded string>" */
2N/A b64s = ldif_type_and_value_with_options(NS_LDAP_BASE64_TAG, value,
2N/A vlen, LDIF_OPT_NOWRAP);
2N/A if (b64s == NULL)
2N/A return (NULL);
2N/A mvlen = strlen(b64s) - NS_LDAP_BASE64_TAG_LDIF_LEN;
2N/A
2N/A /*
2N/A * change "\1{base64}:: <encoded string>" into
2N/A * "\1{base64}<encoded string>
2N/A */
2N/A (void) memmove(b64s + NS_LDAP_BASE64_TAG_LEN,
2N/A b64s + NS_LDAP_BASE64_TAG_LDIF_LEN, mvlen);
2N/A /* remove the newline character at the end */
2N/A b64s[NS_LDAP_BASE64_TAG_LEN + mvlen - 1] = '\0';
2N/A
2N/A return (b64s);
2N/A}
2N/A
2N/A/*
2N/A * Convert a single ldap entry from a LDAPMessage
2N/A * into an ns_ldap_entry structure.
2N/A * Schema map the entry if specified in flags
2N/A */
2N/A
2N/Astatic int
2N/A__s_api_cvtEntry(LDAP *ld,
2N/A const char *service,
2N/A LDAPMessage *e,
2N/A int flags,
2N/A ns_ldap_entry_t **ret,
2N/A ns_ldap_error_t **error,
2N/A ns_ldap_range_info_t **range_info_p)
2N/A{
2N/A
2N/A ns_ldap_entry_t *ep = NULL;
2N/A ns_ldap_attr_t **ap = NULL;
2N/A BerElement *ber = NULL;
2N/A char *attr = NULL;
2N/A char *cp;
2N/A struct berval **bvals = NULL;
2N/A char **mapping;
2N/A char *dn;
2N/A int nAttrs = 0;
2N/A int i, j, k = 0;
2N/A char **gecos_mapping = NULL;
2N/A int gecos_val_index[3] = { -1, -1, -1};
2N/A char errstr[MAXERROR];
2N/A boolean_t schema_mapping_existed = B_FALSE;
2N/A boolean_t gecos_mapping_existed = B_FALSE;
2N/A boolean_t gecos_attr_matched;
2N/A boolean_t auto_service = B_FALSE;
2N/A boolean_t group_service = B_FALSE;
2N/A boolean_t passwd_service = B_FALSE;
2N/A boolean_t cvtdn = B_FALSE;
2N/A boolean_t first_range = B_TRUE;
2N/A boolean_t proc_range = B_FALSE;
2N/A char attr_and_range[NS_LDAP_ATTR_AND_RANGE_SIZE];
2N/A char *attr_to_get;
2N/A int rc = NS_LDAP_SUCCESS;
2N/A ns_ldap_range_attr_t *range_attr;
2N/A
2N/A if (e == NULL || ret == NULL || error == NULL)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A *error = NULL;
2N/A if (*range_info_p != NULL) {
2N/A first_range = B_FALSE;
2N/A proc_range = B_TRUE;
2N/A }
2N/A
2N/A ep = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t));
2N/A if (ep == NULL)
2N/A return (NS_LDAP_MEMORY);
2N/A
2N/A if (service != NULL) {
2N/A if (strncasecmp(service, "auto_", 5) == 0 ||
2N/A strcasecmp(service, "automount") == 0)
2N/A auto_service = B_TRUE;
2N/A else if (strcasecmp(service, "group") == 0)
2N/A group_service = B_TRUE;
2N/A else if (strcasecmp(service, "passwd") == 0)
2N/A passwd_service = B_TRUE;
2N/A }
2N/A
2N/A /*
2N/A * see if schema mapping existed for the given service
2N/A */
2N/A mapping = __ns_ldap_getOrigAttribute(service,
2N/A NS_HASH_SCHEMA_MAPPING_EXISTED);
2N/A if (mapping) {
2N/A schema_mapping_existed = B_TRUE;
2N/A __s_api_free2dArray(mapping);
2N/A mapping = NULL;
2N/A } else if (auto_service) {
2N/A /*
2N/A * If service == auto_* and no
2N/A * schema mapping found
2N/A * then try automount
2N/A * There is certain case that schema mapping exist
2N/A * but __ns_ldap_getOrigAttribute(service,
2N/A * NS_HASH_SCHEMA_MAPPING_EXISTED);
2N/A * returns NULL.
2N/A * e.g.
2N/A * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
2N/A * NS_LDAP_OBJECTCLASSMAP = automount:automountMap=MynisMap
2N/A * NS_LDAP_OBJECTCLASSMAP = automount:automount=MynisObject
2N/A *
2N/A * Make a check for schema_mapping_existed here
2N/A * so later on __s_api_convert_automountmapname won't be called
2N/A * unnecessarily. It is also used for attribute mapping
2N/A * and objectclass mapping.
2N/A */
2N/A mapping = __ns_ldap_getOrigAttribute("automount",
2N/A NS_HASH_SCHEMA_MAPPING_EXISTED);
2N/A if (mapping) {
2N/A schema_mapping_existed = B_TRUE;
2N/A __s_api_free2dArray(mapping);
2N/A mapping = NULL;
2N/A }
2N/A }
2N/A
2N/A nAttrs = 1; /* start with 1, 0 is for the DN attr */
2N/A for (attr = ldap_first_attribute(ld, e, &ber); attr != NULL;
2N/A attr = ldap_next_attribute(ld, e, ber)) {
2N/A nAttrs++;
2N/A if (strstr(attr, ";range=") != NULL) {
2N/A rc = update_range_info(first_range, attr,
2N/A range_info_p);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A ldap_memfree(attr);
2N/A attr = NULL;
2N/A ber_free(ber, 0);
2N/A ber = NULL;
2N/A __ns_ldap_freeEntry(ep);
2N/A ep = NULL;
2N/A return (rc);
2N/A }
2N/A }
2N/A ldap_memfree(attr);
2N/A attr = NULL;
2N/A }
2N/A ber_free(ber, 0);
2N/A ber = NULL;
2N/A
2N/A if (!proc_range && *range_info_p != NULL)
2N/A proc_range = B_TRUE;
2N/A
2N/A ep->attr_count = nAttrs;
2N/A
2N/A /*
2N/A * add 1 for "gecos" 1 to N attribute mapping,
2N/A * just in case it is needed.
2N/A * ep->attr_count will be updated later if that is true.
2N/A */
2N/A ap = (ns_ldap_attr_t **)calloc(ep->attr_count + 1,
2N/A sizeof (ns_ldap_attr_t *));
2N/A if (ap == NULL) {
2N/A __ns_ldap_freeEntry(ep);
2N/A ep = NULL;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A ep->attr_pair = ap;
2N/A
2N/A /* DN attribute */
2N/A dn = ldap_get_dn(ld, e);
2N/A ap[0] = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
2N/A if (ap[0] == NULL)
2N/A goto free_dn_and_return;
2N/A ap[0]->attrname = strdup("dn");
2N/A if (ap[0]->attrname == NULL)
2N/A goto free_dn_and_return;
2N/A if (proc_range && first_range) {
2N/A (*range_info_p)->dn = strdup(dn);
2N/A if ((*range_info_p)->dn == NULL)
2N/A goto free_dn_and_return;
2N/A }
2N/A
2N/A ap[0]->value_count = 1;
2N/A if ((ap[0]->attrvalue = (char **)
2N/A calloc(2, sizeof (char *))) == NULL)
2N/A goto free_dn_and_return;
2N/A
2N/A /* attribute-map and normalize the entry DN if needed */
2N/A if ((flags & NS_LDAP_NOT_CVT_DN) == 0) {
2N/A if (schema_mapping_existed)
2N/A ap[0]->attrvalue[0] = _cvtDN(service, dn, B_TRUE);
2N/A } else {
2N/A /*
2N/A * To speed up group member DN processing, we need to
2N/A * normalize the entry DN of a passwd or group entry.
2N/A * Such DNs will later be stored in cache if needed.
2N/A */
2N/A if (group_service || passwd_service)
2N/A ap[0]->attrvalue[0] = _cvtDN(service, dn, B_FALSE);
2N/A }
2N/A if (ap[0]->attrvalue[0] == NULL) {
2N/A ap[0]->attrvalue[0] = strdup(dn);
2N/A if (ap[0]->attrvalue[0] == NULL)
2N/A goto free_dn_and_return;
2N/A }
2N/A ldap_memfree(dn);
2N/A dn = NULL;
2N/A
2N/A if ((flags & NS_LDAP_NOMAP) == 0 && auto_service &&
2N/A schema_mapping_existed) {
2N/A rc = __s_api_convert_automountmapname(service,
2N/A &ap[0]->attrvalue[0], error);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A __ns_ldap_freeEntry(ep);
2N/A ep = NULL;
2N/A return (rc);
2N/A }
2N/A }
2N/A
2N/A /* other attributes */
2N/A for (attr = ldap_first_attribute(ld, e, &ber), j = 1;
2N/A attr != NULL && j != nAttrs;
2N/A attr = ldap_next_attribute(ld, e, ber), j++) {
2N/A
2N/A attr_to_get = attr;
2N/A
2N/A /* allocate new attr name */
2N/A if ((ap[j] = (ns_ldap_attr_t *)
2N/A calloc(1, sizeof (ns_ldap_attr_t))) == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A
2N/A /*
2N/A * Range result ? Not all values returned ? Then
2N/A * attr should looks like: <attr type>;range=n1-n2
2N/A * where n2 may be '*', i.e., end of range.
2N/A */
2N/A range_attr = NULL;
2N/A if (proc_range) {
2N/A ns_ldap_range_attr_t *ra;
2N/A char *cp;
2N/A
2N/A ra = (*range_info_p)->range_attr;
2N/A while (ra != NULL) {
2N/A if (strncasecmp(attr, ra->attr_and_range,
2N/A ra->attr_len + 1) == 0) {
2N/A range_attr = ra;
2N/A /*
2N/A * For now, ra->received_ranges will
2N/A * have the first range of values. For
2N/A * subsequent range searches, values
2N/A * found in ra->current_range will be
2N/A * appended to it in __s_api_getEntry.
2N/A * So it would represent the
2N/A * accumulation of all of the ranges
2N/A * received so far.
2N/A */
2N/A if (first_range)
2N/A ra->received_ranges = ap[j];
2N/A else
2N/A ra->current_range = ap[j];
2N/A
2N/A /* copy attribute type + range */
2N/A (void) strlcpy(attr_and_range, attr,
2N/A NS_LDAP_ATTR_AND_RANGE_SIZE);
2N/A attr_to_get = attr_and_range;
2N/A /* no need for the range part now */
2N/A cp = strchr(attr, ';');
2N/A *cp = '\0';
2N/A }
2N/A ra = ra->next;
2N/A }
2N/A }
2N/A
2N/A if ((flags & NS_LDAP_NOMAP) || !schema_mapping_existed)
2N/A mapping = NULL;
2N/A else
2N/A mapping = __ns_ldap_getOrigAttribute(service, attr);
2N/A
2N/A if (mapping == NULL && auto_service &&
2N/A schema_mapping_existed && (flags & NS_LDAP_NOMAP) == 0)
2N/A /*
2N/A * if service == auto_* and no schema mapping found
2N/A * and schema_mapping_existed is TRUE and NS_LDAP_NOMAP
2N/A * is not set then try automount e.g.
2N/A * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
2N/A */
2N/A mapping = __ns_ldap_getOrigAttribute("automount",
2N/A attr);
2N/A
2N/A if (mapping == NULL) {
2N/A if ((ap[j]->attrname = strdup(attr)) == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A } else {
2N/A /*
2N/A * for "gecos" 1 to N mapping,
2N/A * do not remove the mapped attribute,
2N/A * just create a new gecos attribute
2N/A * and append it to the end of the attribute list
2N/A */
2N/A if (strcasecmp(mapping[0], "gecos") == 0) {
2N/A ap[j]->attrname = strdup(attr);
2N/A gecos_mapping_existed = B_TRUE;
2N/A } else {
2N/A ap[j]->attrname = strdup(mapping[0]);
2N/A }
2N/A if (ap[j]->attrname == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A
2N/A if (range_attr != NULL) {
2N/A range_attr->mapped_name = strdup(mapping[0]);
2N/A if (range_attr->mapped_name == NULL) {
2N/A free(ap[j]->attrname);
2N/A ap[j]->attrname = NULL;
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * 1 to N attribute mapping processing
2N/A * is only done for "gecos"
2N/A */
2N/A
2N/A if (strcasecmp(mapping[0], "gecos") == 0) {
2N/A /*
2N/A * get attribute mapping for "gecos",
2N/A * need to know the number and order of the
2N/A * mapped attributes
2N/A */
2N/A if (gecos_mapping == NULL) {
2N/A gecos_mapping =
2N/A __ns_ldap_getMappedAttributes(
2N/A service, mapping[0]);
2N/A if (gecos_mapping == NULL ||
2N/A gecos_mapping[0] == NULL) {
2N/A /*
2N/A * this should never happens,
2N/A * syslog the error
2N/A */
2N/A (void) sprintf(errstr,
2N/A gettext(
2N/A "Attribute mapping "
2N/A "inconsistency "
2N/A "found for attributes "
2N/A "'%s' and '%s'."),
2N/A mapping[0], attr);
2N/A syslog(LOG_ERR, "libsldap: %s",
2N/A errstr);
2N/A
2N/A rc = NS_LDAP_INTERNAL;
2N/A goto err_out;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * is this attribute the 1st, 2nd, or
2N/A * 3rd attr in the mapping list?
2N/A */
2N/A gecos_attr_matched = B_FALSE;
2N/A for (i = 0; i < 3 && gecos_mapping[i]; i++) {
2N/A if (gecos_mapping[i] &&
2N/A strcasecmp(gecos_mapping[i],
2N/A attr) == 0) {
2N/A gecos_val_index[i] = j;
2N/A gecos_attr_matched = B_TRUE;
2N/A break;
2N/A }
2N/A }
2N/A if (!gecos_attr_matched) {
2N/A /*
2N/A * Not match found.
2N/A * This should never happens,
2N/A * syslog the error
2N/A */
2N/A (void) sprintf(errstr,
2N/A gettext(
2N/A "Attribute mapping "
2N/A "inconsistency "
2N/A "found for attributes "
2N/A "'%s' and '%s'."),
2N/A mapping[0], attr);
2N/A syslog(LOG_ERR, "libsldap: %s", errstr);
2N/A
2N/A rc = NS_LDAP_INTERNAL;
2N/A goto err_out;
2N/A }
2N/A }
2N/A __s_api_free2dArray(mapping);
2N/A mapping = NULL;
2N/A }
2N/A
2N/A /*
2N/A * Need to process group member or memberof in DN format ?
2N/A */
2N/A cvtdn = B_FALSE;
2N/A if ((group_service &&
2N/A (strcasecmp(ap[j]->attrname, "member") == 0 ||
2N/A strcasecmp(ap[j]->attrname, "uniquemember") == 0 ||
2N/A strcasecmp(ap[j]->attrname, "memberof") == 0)) ||
2N/A (passwd_service &&
2N/A strcasecmp(ap[j]->attrname, "memberof") == 0)) {
2N/A cvtdn = B_TRUE;
2N/A }
2N/A
2N/A if ((bvals = ldap_get_values_len(ld, e, attr_to_get)) == NULL) {
2N/A ldap_memfree(attr);
2N/A attr = NULL;
2N/A continue;
2N/A }
2N/A
2N/A if ((ap[j]->value_count = ldap_count_values_len(bvals)) == 0) {
2N/A ldap_value_free_len(bvals);
2N/A bvals = NULL;
2N/A ldap_memfree(attr);
2N/A attr = NULL;
2N/A continue;
2N/A }
2N/A
2N/A ap[j]->attrvalue = (char **)
2N/A calloc(ap[j]->value_count + 1, sizeof (char *));
2N/A if (ap[j]->attrvalue == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A
2N/A for (i = 0; i < ap[j]->value_count; i++) {
2N/A boolean_t binary_data = B_FALSE;
2N/A /* check for binary data if length not zero */
2N/A if ((flags & NS_LDAP_BASE64_BINARY_ATTR_VALUE) != 0) {
2N/A cp = bvals[i]->bv_val;
2N/A for (k = 1; k <= bvals[i]->bv_len;
2N/A k++, cp++) {
2N/A if (!LDIF_CONSERVATIVE_CHAR(*cp)) {
2N/A binary_data = B_TRUE;
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A if (binary_data) {
2N/A /* encode the data in base64 */
2N/A ap[j]->attrvalue[i] =
2N/A b64_encode(bvals[i]->bv_val,
2N/A bvals[i]->bv_len);
2N/A if (ap[j]->attrvalue[i] == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A } else {
2N/A ap[j]->attrvalue[i] = calloc(1,
2N/A bvals[i]->bv_len + 1);
2N/A if (ap[j]->attrvalue[i] == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A if (bvals[i]->bv_len == 0)
2N/A continue;
2N/A (void) memcpy(ap[j]->attrvalue[i],
2N/A bvals[i]->bv_val, bvals[i]->bv_len);
2N/A }
2N/A }
2N/A
2N/A /* map object classes if necessary */
2N/A if ((flags & NS_LDAP_NOMAP) == 0 &&
2N/A schema_mapping_existed && ap[j]->attrname &&
2N/A strcasecmp(ap[j]->attrname, "objectclass") == 0) {
2N/A for (k = 0; k < ap[j]->value_count; k++) {
2N/A mapping = __ns_ldap_getOrigObjectClass(
2N/A service, ap[j]->attrvalue[k]);
2N/A
2N/A if (mapping == NULL && auto_service)
2N/A /*
2N/A * if service == auto_* and no
2N/A * schema mapping found
2N/A * then try automount
2N/A */
2N/A mapping =
2N/A __ns_ldap_getOrigObjectClass(
2N/A "automount", ap[j]->attrvalue[k]);
2N/A
2N/A if (mapping != NULL) {
2N/A free(ap[j]->attrvalue[k]);
2N/A ap[j]->attrvalue[k] =
2N/A strdup(mapping[0]);
2N/A __s_api_free2dArray(mapping);
2N/A mapping = NULL;
2N/A }
2N/A if (ap[j]->attrvalue[k] == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A }
2N/A } else {
2N/A /*
2N/A * Normalize group member or memberof
2N/A * DN but don't map attributes.
2N/A */
2N/A if (cvtdn) {
2N/A for (k = 0; k < ap[j]->value_count; k++) {
2N/A char *old, *new;
2N/A old = ap[j]->attrvalue[k];
2N/A new = _cvtDN(service, old, B_FALSE);
2N/A if (new != old) {
2N/A free(old);
2N/A ap[j]->attrvalue[k] = new;
2N/A }
2N/A
2N/A if (ap[j]->attrvalue[k] == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A }
2N/A }
2N/A }
2N/A
2N/A ldap_value_free_len(bvals);
2N/A bvals = NULL;
2N/A
2N/A ldap_memfree(attr);
2N/A attr = NULL;
2N/A } /* end of other attributes loop */
2N/A
2N/A ber_free(ber, 0);
2N/A ber = NULL;
2N/A if (gecos_mapping) {
2N/A __s_api_free2dArray(gecos_mapping);
2N/A gecos_mapping = NULL;
2N/A }
2N/A
2N/A /* special processing for gecos 1 to up to 3 attribute mapping */
2N/A if (schema_mapping_existed && gecos_mapping_existed) {
2N/A
2N/A int f = -1;
2N/A
2N/A for (i = 0; i < 3; i++) {
2N/A k = gecos_val_index[i];
2N/A
2N/A /*
2N/A * f is the index of the first returned
2N/A * attribute which "gecos" attribute mapped to
2N/A */
2N/A if (k != -1 && f == -1)
2N/A f = k;
2N/A
2N/A if (k != -1 && ap[k]->value_count > 0 &&
2N/A ap[k]->attrvalue[0] &&
2N/A strlen(ap[k]->attrvalue[0]) > 0) {
2N/A
2N/A if (k == f) {
2N/A /*
2N/A * Create and fill in the last reserved
2N/A * ap with the data from the "gecos"
2N/A * mapping attributes
2N/A */
2N/A ap[nAttrs] = (ns_ldap_attr_t *)
2N/A calloc(1,
2N/A sizeof (ns_ldap_attr_t));
2N/A if (ap[nAttrs] == NULL) {
2N/A __ns_ldap_freeEntry(ep);
2N/A ep = NULL;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A ap[nAttrs]->attrvalue = (char **)calloc(
2N/A 2, sizeof (char *));
2N/A if (ap[nAttrs]->attrvalue == NULL) {
2N/A __ns_ldap_freeEntry(ep);
2N/A ep = NULL;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A /* add 1 more for a possible "," */
2N/A ap[nAttrs]->attrvalue[0] =
2N/A (char *)calloc(
2N/A strlen(ap[f]->attrvalue[0]) +
2N/A 2, 1);
2N/A if (ap[nAttrs]->attrvalue[0] == NULL) {
2N/A __ns_ldap_freeEntry(ep);
2N/A ep = NULL;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A (void) strcpy(ap[nAttrs]->attrvalue[0],
2N/A ap[f]->attrvalue[0]);
2N/A
2N/A ap[nAttrs]->attrname = strdup("gecos");
2N/A if (ap[nAttrs]->attrname == NULL) {
2N/A __ns_ldap_freeEntry(ep);
2N/A ep = NULL;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A
2N/A ap[nAttrs]->value_count = 1;
2N/A ep->attr_count = nAttrs + 1;
2N/A
2N/A } else {
2N/A char *tmp = NULL;
2N/A
2N/A /*
2N/A * realloc to add "," and
2N/A * ap[k]->attrvalue[0]
2N/A */
2N/A tmp = (char *)realloc(
2N/A ap[nAttrs]->attrvalue[0],
2N/A strlen(ap[nAttrs]->
2N/A attrvalue[0]) +
2N/A strlen(ap[k]->
2N/A attrvalue[0]) + 2);
2N/A if (tmp == NULL) {
2N/A __ns_ldap_freeEntry(ep);
2N/A ep = NULL;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A ap[nAttrs]->attrvalue[0] = tmp;
2N/A (void) strcat(ap[nAttrs]->attrvalue[0],
2N/A ",");
2N/A (void) strcat(ap[nAttrs]->attrvalue[0],
2N/A ap[k]->attrvalue[0]);
2N/A }
2N/A }
2N/A }
2N/A }
2N/A
2N/A *ret = ep;
2N/A return (NS_LDAP_SUCCESS);
2N/A
2N/Afree_dn_and_return:
2N/A ldap_memfree(dn);
2N/A __ns_ldap_freeEntry(ep);
2N/A return (NS_LDAP_MEMORY);
2N/A
2N/Aerr_out:
2N/A if (mapping != NULL)
2N/A __s_api_free2dArray(mapping);
2N/A if (bvals != NULL)
2N/A ldap_value_free_len(bvals);
2N/A if (attr != NULL)
2N/A ldap_memfree(attr);
2N/A if (ber != NULL)
2N/A ber_free(ber, 0);
2N/A if (gecos_mapping)
2N/A __s_api_free2dArray(gecos_mapping);
2N/A __ns_ldap_freeEntry(ep);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * The ns_ldap_entry_t generated by __s_api_cvtEntry() may contain
2N/A * duplicate attributes for an range attribute. These duplicate
2N/A * ones are caused by libldap when it returns attributes such
2N/A * as "member" and "member;range=0-1499" together. This function
2N/A * keeps the short one and removes the one with option.
2N/A */
2N/Astatic void
2N/Aremove_dup_range_attrs(ns_ldap_entry_t *entry, ns_ldap_range_info_t *info)
2N/A{
2N/A ns_ldap_attr_t *eAttr;
2N/A ns_ldap_range_attr_t *attr;
2N/A int i, j, cnt;
2N/A char *attrname;
2N/A
2N/A /*
2N/A * Remove duplicate empty attributes, such as member or memberof,
2N/A * in the result ns_ldap_entry_t entry.
2N/A */
2N/A attr = info->range_attr;
2N/A while (attr != NULL) {
2N/A /*
2N/A * Attribute name in entry may be mapped to a different name
2N/A * due to attribute mapping. The one containing range
2N/A * option info is an unmapped one, so use the mapped
2N/A * one saved in ns_ldap_range attr_t to find duplicate.
2N/A */
2N/A if (attr->mapped_name != NULL) {
2N/A attrname = attr->mapped_name;
2N/A } else {
2N/A attrname = attr->attr_and_range;
2N/A /* No need for the range option info now */
2N/A attrname[attr->attr_len] = '\0';
2N/A }
2N/A
2N/A cnt = entry->attr_count;
2N/A for (i = 0; i < cnt; i++) {
2N/A eAttr = entry->attr_pair[i];
2N/A if (eAttr->value_count != 0)
2N/A continue;
2N/A if (strcasecmp(attrname, eAttr->attrname) == 0) {
2N/A free(eAttr->attrname);
2N/A free(eAttr);
2N/A for (j = i; j < cnt - 1; j++) {
2N/A entry->attr_pair[j] =
2N/A entry->attr_pair[j + 1];
2N/A }
2N/A entry->attr_pair[j] = NULL;
2N/A entry->attr_count--;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A /* restore the range option info if needed */
2N/A if (attr->mapped_name == NULL) {
2N/A attrname[attr->attr_len] = ';';
2N/A }
2N/A
2N/A attr = attr->next;
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/A__s_api_getEntry(ns_ldap_cookie_t *cookie)
2N/A{
2N/A ns_ldap_entry_t *curEntry = NULL;
2N/A ns_ldap_range_info_t *info;
2N/A ns_ldap_range_attr_t *attr;
2N/A int ret, i;
2N/A
2N/A#ifdef DEBUG
2N/A (void) fprintf(stderr, "__s_api_getEntry START\n");
2N/A#endif
2N/A
2N/A if (cookie->resultMsg == NULL) {
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A }
2N/A
2N/A ret = __s_api_cvtEntry(cookie->conn->ld, cookie->service,
2N/A cookie->resultMsg, cookie->i_flags,
2N/A &curEntry, &cookie->errorp, &cookie->range_info);
2N/A if (ret != NS_LDAP_SUCCESS)
2N/A goto out;
2N/A
2N/A if (!cookie->get_next_range) {
2N/A if (cookie->result == NULL) {
2N/A cookie->result = (ns_ldap_result_t *)
2N/A calloc(1, sizeof (ns_ldap_result_t));
2N/A if (cookie->result == NULL) {
2N/A ret = NS_LDAP_MEMORY;
2N/A goto out;
2N/A }
2N/A cookie->result->entry = curEntry;
2N/A cookie->nextEntry = curEntry;
2N/A } else {
2N/A cookie->nextEntry->next = curEntry;
2N/A cookie->nextEntry = curEntry;
2N/A }
2N/A cookie->result->entries_count++;
2N/A }
2N/A
2N/A if (cookie->i_extra_info_attr != NULL &&
2N/A cookie->extra_info == NULL)
2N/A set_extra_info(cookie);
2N/A
2N/A if (cookie->range_info == NULL)
2N/A return (NS_LDAP_SUCCESS);
2N/A
2N/A info = cookie->range_info;
2N/A /*
2N/A * If just gotten the first range, remove duplicate attribute types,
2N/A * i.e., keep "member" and not "member;range=0-1499". Otherwise,
2N/A * merge this range of values with the previous ones.
2N/A */
2N/A if (!cookie->get_next_range) {
2N/A cookie->get_next_range = B_TRUE;
2N/A remove_dup_range_attrs(curEntry, info);
2N/A info->attr_to_search = (char **)calloc(info->attr_count + 1,
2N/A sizeof (char *));
2N/A if (info->attr_to_search == NULL) {
2N/A ret = NS_LDAP_MEMORY;
2N/A goto out;
2N/A }
2N/A } else {
2N/A uint_t old_count, new_count;
2N/A char **tmp, **new_values;
2N/A ns_ldap_range_attr_t *prev, *next;
2N/A
2N/A /*
2N/A * Reallocate the received_ranges value array and add the
2N/A * current one to the end of it.
2N/A */
2N/A for (prev = NULL, attr = info->range_attr; attr != NULL;
2N/A attr = next) {
2N/A old_count = attr->received_ranges->value_count;
2N/A new_count = old_count +
2N/A attr->current_range->value_count;
2N/A tmp = (char **)realloc(attr->received_ranges->attrvalue,
2N/A new_count * sizeof (char *));
2N/A if (tmp == NULL) {
2N/A ret = NS_LDAP_MEMORY;
2N/A goto out;
2N/A }
2N/A attr->received_ranges->attrvalue = tmp;
2N/A new_values = tmp + old_count;
2N/A (void) memcpy(new_values,
2N/A attr->current_range->attrvalue,
2N/A attr->current_range->value_count * sizeof (char *));
2N/A attr->received_ranges->value_count = new_count;
2N/A
2N/A /*
2N/A * Free the current (not first) ns_ldap_entry.
2N/A * The attribute value array itself needs to be
2N/A * freed, but not the value strings. Since the
2N/A * pointers to these strings have just been
2N/A * copied into the first ns_ldap_entry's value
2N/A * array.
2N/A */
2N/A free(attr->current_range->attrvalue);
2N/A attr->current_range->attrvalue = NULL;
2N/A attr->current_range->value_count = 0;
2N/A attr->current_range = NULL;
2N/A __ns_ldap_freeEntry(curEntry);
2N/A curEntry = NULL;
2N/A
2N/A /* clean up the range control info if last range */
2N/A if (attr->range_done) {
2N/A next = attr->next;
2N/A if (attr->attr_and_range != NULL) {
2N/A free(attr->attr_and_range);
2N/A attr->attr_and_range = NULL;
2N/A }
2N/A if (info->range_attr == attr)
2N/A info->range_attr = next;
2N/A else
2N/A prev->next = next;
2N/A free(attr);
2N/A info->attr_count--;
2N/A } else {
2N/A prev = attr;
2N/A next = attr->next;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Generate only once the extra infomation
2N/A * (operational attributes) if requested.
2N/A * Then exit with NS_LDAP_SUCCESS.
2N/A */
2N/A if (info->attr_count == 0) {
2N/A if (cookie->i_extra_info_attr != NULL &&
2N/A cookie->extra_info == NULL)
2N/A set_extra_info(cookie);
2N/A ret = NS_LDAP_SUCCESS;
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * set up the attributes (with updated range numbers)
2N/A * for the next search of the same DN
2N/A */
2N/A attr = info->range_attr;
2N/A for (i = 0; attr != NULL; attr = attr->next, i++) {
2N/A info->attr_to_search[i] = attr->attr_and_range;
2N/A }
2N/A info->attr_to_search[i] = NULL;
2N/A
2N/A return (NS_LDAP_SUCCESS);
2N/Aout:
2N/A if (cookie->range_info != NULL)
2N/A free_range_info(&cookie->range_info);
2N/A if (ret != NS_LDAP_SUCCESS && cookie->extra_info != NULL) {
2N/A __ns_ldap_freeEntry(cookie->extra_info);
2N/A cookie->extra_info = NULL;
2N/A }
2N/A if (curEntry != NULL)
2N/A __ns_ldap_freeEntry(curEntry);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/Astatic int
2N/A__s_api_get_cachemgr_data(const char *type,
2N/A const char *from, char **to)
2N/A{
2N/A union {
2N/A ldap_data_t s_d;
2N/A char s_b[DOORBUFFERSIZE];
2N/A } space;
2N/A ldap_data_t *sptr;
2N/A int ndata;
2N/A int adata;
2N/A int rc;
2N/A
2N/A#ifdef DEBUG
2N/A (void) fprintf(stderr, "__s_api_get_cachemgr_data START\n");
2N/A#endif
2N/A /*
2N/A * We are not going to perform DN to domain mapping
2N/A * in the Standalone mode
2N/A */
2N/A if (__s_api_isStandalone()) {
2N/A return (-1);
2N/A }
2N/A
2N/A if (from == NULL || from[0] == '\0' || to == NULL)
2N/A return (-1);
2N/A
2N/A *to = NULL;
2N/A (void) memset(space.s_b, 0, DOORBUFFERSIZE);
2N/A
2N/A space.s_d.ldap_call.ldap_callnumber = GETCACHE;
2N/A (void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
2N/A DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
2N/A "%s%s%s",
2N/A type,
2N/A DOORLINESEP,
2N/A from);
2N/A ndata = sizeof (space);
2N/A adata = sizeof (ldap_call_t) +
2N/A strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
2N/A sptr = &space.s_d;
2N/A
2N/A rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
2N/A if (rc != NS_CACHE_SUCCESS)
2N/A return (-1);
2N/A else
2N/A *to = strdup(sptr->ldap_ret.ldap_u.buff);
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/Astatic int
2N/A__s_api_set_cachemgr_data(const char *type,
2N/A const char *from, const char *to)
2N/A{
2N/A union {
2N/A ldap_data_t s_d;
2N/A char s_b[DOORBUFFERSIZE];
2N/A } space;
2N/A ldap_data_t *sptr;
2N/A int ndata;
2N/A int adata;
2N/A int rc;
2N/A
2N/A#ifdef DEBUG
2N/A (void) fprintf(stderr, "__s_api_set_cachemgr_data START\n");
2N/A#endif
2N/A /*
2N/A * We are not going to perform DN to domain mapping
2N/A * in the Standalone mode
2N/A */
2N/A if (__s_api_isStandalone()) {
2N/A return (-1);
2N/A }
2N/A
2N/A if ((from == NULL) || (from[0] == '\0') ||
2N/A (to == NULL) || (to[0] == '\0'))
2N/A return (-1);
2N/A
2N/A (void) memset(space.s_b, 0, DOORBUFFERSIZE);
2N/A
2N/A space.s_d.ldap_call.ldap_callnumber = SETCACHE;
2N/A (void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
2N/A DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
2N/A "%s%s%s%s%s",
2N/A type,
2N/A DOORLINESEP,
2N/A from,
2N/A DOORLINESEP,
2N/A to);
2N/A
2N/A ndata = sizeof (space);
2N/A adata = sizeof (ldap_call_t) +
2N/A strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
2N/A sptr = &space.s_d;
2N/A
2N/A rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
2N/A if (rc != NS_CACHE_SUCCESS)
2N/A return (-1);
2N/A
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/A
2N/Astatic char *
2N/A__s_api_remove_rdn_space(char *rdn)
2N/A{
2N/A char *tf, *tl, *vf, *vl, *eqsign;
2N/A
2N/A /* if no space(s) to remove, return */
2N/A if (strchr(rdn, SPACETOK) == NULL)
2N/A return (rdn);
2N/A
2N/A /* if no '=' separator, return */
2N/A eqsign = strchr(rdn, '=');
2N/A if (eqsign == NULL)
2N/A return (rdn);
2N/A
2N/A tf = rdn;
2N/A tl = eqsign - 1;
2N/A vf = eqsign + 1;
2N/A vl = rdn + strlen(rdn) - 1;
2N/A
2N/A /* now two strings, type and value */
2N/A *eqsign = '\0';
2N/A
2N/A /* remove type's leading spaces */
2N/A while (tf < tl && *tf == SPACETOK)
2N/A tf++;
2N/A /* remove type's trailing spaces */
2N/A while (tf < tl && *tl == SPACETOK)
2N/A tl--;
2N/A /* add '=' separator back */
2N/A *(++tl) = '=';
2N/A /* remove value's leading spaces */
2N/A while (vf < vl && *vf == SPACETOK)
2N/A vf++;
2N/A /* remove value's trailing spaces */
2N/A while (vf < vl && *vl == SPACETOK)
2N/A *vl-- = '\0';
2N/A
2N/A /* move value up if necessary */
2N/A if (vf != tl + 1)
2N/A (void) strcpy(tl + 1, vf);
2N/A
2N/A return (tf);
2N/A}
2N/A
2N/Astatic
2N/Ans_ldap_cookie_t *
2N/Ainit_search_state_machine()
2N/A{
2N/A ns_ldap_cookie_t *cookie;
2N/A ns_config_t *cfg;
2N/A
2N/A cookie = (ns_ldap_cookie_t *)calloc(1, sizeof (ns_ldap_cookie_t));
2N/A if (cookie == NULL)
2N/A return (NULL);
2N/A cookie->state = INIT;
2N/A /* assign other state variables */
2N/A cfg = __s_api_loadrefresh_config();
2N/A cookie->connectionId = -1;
2N/A if (cfg == NULL ||
2N/A cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_ptype == NS_UNKNOWN) {
2N/A cookie->search_timeout.tv_sec = NS_DEFAULT_SEARCH_TIMEOUT;
2N/A } else {
2N/A cookie->search_timeout.tv_sec =
2N/A cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_i;
2N/A }
2N/A if (cfg != NULL)
2N/A __s_api_release_config(cfg);
2N/A cookie->search_timeout.tv_usec = 0;
2N/A
2N/A return (cookie);
2N/A}
2N/A
2N/Astatic void
2N/Adelete_search_cookie(ns_ldap_cookie_t *cookie)
2N/A{
2N/A if (cookie == NULL)
2N/A return;
2N/A if (cookie->connectionId > -1)
2N/A DropConnection(cookie->connectionId, cookie->i_flags);
2N/A if (cookie->filter)
2N/A free(cookie->filter);
2N/A if (cookie->i_filter)
2N/A free(cookie->i_filter);
2N/A if (cookie->service)
2N/A free(cookie->service);
2N/A if (cookie->sdlist)
2N/A (void) __ns_ldap_freeSearchDescriptors(&(cookie->sdlist));
2N/A if (cookie->result)
2N/A (void) __ns_ldap_freeResult(&cookie->result);
2N/A if (cookie->extra_info)
2N/A (void) __ns_ldap_freeEntry(cookie->extra_info);
2N/A cookie->extra_info = NULL;
2N/A if (cookie->attribute)
2N/A __s_api_free2dArray(cookie->attribute);
2N/A if (cookie->errorp)
2N/A (void) __ns_ldap_freeError(&cookie->errorp);
2N/A if (cookie->referral_list)
2N/A __s_api_deleteReferral(cookie->referral_list);
2N/A if (cookie->basedn)
2N/A free(cookie->basedn);
2N/A if (cookie->ctrlCookie)
2N/A ber_bvfree(cookie->ctrlCookie);
2N/A _freeControlList(&cookie->p_serverctrls);
2N/A if (cookie->resultctrl)
2N/A ldap_controls_free(cookie->resultctrl);
2N/A if (cookie->range_info)
2N/A free_range_info(&cookie->range_info);
2N/A free(cookie);
2N/A}
2N/A
2N/Astatic int
2N/Aget_mapped_filter(ns_ldap_cookie_t *cookie, char **new_filter)
2N/A{
2N/A
2N/A typedef struct filter_mapping_info {
2N/A char oc_or_attr;
2N/A char *name_start;
2N/A char *name_end;
2N/A char *veq_pos;
2N/A char *from_name;
2N/A char *to_name;
2N/A char **mapping;
2N/A } filter_mapping_info_t;
2N/A
2N/A char *c, *last_copied;
2N/A char *filter_c, *filter_c_next;
2N/A char *key, *tail, *head;
2N/A char errstr[MAXERROR];
2N/A int num_eq = 0, num_veq = 0;
2N/A int in_quote = FALSE;
2N/A int is_value = FALSE;
2N/A int i, j, oc_len, len;
2N/A int at_least_one = FALSE;
2N/A filter_mapping_info_t **info, *info1;
2N/A char **mapping;
2N/A char *service, *filter, *err;
2N/A int auto_service = FALSE;
2N/A
2N/A if (cookie == NULL || new_filter == NULL)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A *new_filter = NULL;
2N/A service = cookie->service;
2N/A filter = cookie->filter;
2N/A
2N/A /*
2N/A * count the number of '=' char
2N/A */
2N/A for (c = filter; *c; c++) {
2N/A if (*c == TOKENSEPARATOR)
2N/A num_eq++;
2N/A }
2N/A
2N/A if (service != NULL && strncasecmp(service, "auto_", 5) == 0)
2N/A auto_service = TRUE;
2N/A
2N/A /*
2N/A * See if schema mapping existed for the given service.
2N/A * If not, just return success.
2N/A */
2N/A mapping = __ns_ldap_getOrigAttribute(service,
2N/A NS_HASH_SCHEMA_MAPPING_EXISTED);
2N/A
2N/A if (mapping == NULL && auto_service)
2N/A /*
2N/A * if service == auto_* and no
2N/A * schema mapping found
2N/A * then try automount
2N/A */
2N/A mapping = __ns_ldap_getOrigAttribute(
2N/A "automount", NS_HASH_SCHEMA_MAPPING_EXISTED);
2N/A
2N/A if (mapping)
2N/A __s_api_free2dArray(mapping);
2N/A else
2N/A return (NS_LDAP_SUCCESS);
2N/A
2N/A /*
2N/A * no '=' sign, just say OK and return nothing
2N/A */
2N/A if (num_eq == 0)
2N/A return (NS_LDAP_SUCCESS);
2N/A
2N/A /*
2N/A * Make a copy of the filter string
2N/A * for saving the name of the objectclasses or
2N/A * attributes that need to be passed to the
2N/A * objectclass or attribute mapping functions.
2N/A * pointer "info->from_name" points to the locations
2N/A * within this string.
2N/A *
2N/A * The input filter string, filter, will be used
2N/A * to indicate where these names start and end.
2N/A * pointers "info->name_start" and "info->name_end"
2N/A * point to locations within the input filter string,
2N/A * and are used at the end of this function to
2N/A * merge the original filter data with the
2N/A * mapped objectclass or attribute names.
2N/A */
2N/A filter_c = strdup(filter);
2N/A if (filter_c == NULL)
2N/A return (NS_LDAP_MEMORY);
2N/A filter_c_next = filter_c;
2N/A
2N/A /*
2N/A * get memory for info arrays
2N/A */
2N/A info = (filter_mapping_info_t **)calloc(num_eq + 1,
2N/A sizeof (filter_mapping_info_t *));
2N/A
2N/A if (info == NULL) {
2N/A free(filter_c);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A
2N/A /*
2N/A * find valid '=' for further processing,
2N/A * ignore the "escaped =" (.i.e. "\="), or
2N/A * "=" in quoted string
2N/A */
2N/A for (c = filter_c; *c; c++) {
2N/A
2N/A switch (*c) {
2N/A case TOKENSEPARATOR:
2N/A if (!in_quote && !is_value) {
2N/A info1 = (filter_mapping_info_t *)calloc(1,
2N/A sizeof (filter_mapping_info_t));
2N/A if (!info1) {
2N/A free(filter_c);
2N/A for (i = 0; i < num_veq; i++)
2N/A free(info[i]);
2N/A free(info);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A info[num_veq] = info1;
2N/A
2N/A /*
2N/A * remember the location of this "="
2N/A */
2N/A info[num_veq++]->veq_pos = c;
2N/A
2N/A /*
2N/A * skip until the end of the attribute value
2N/A */
2N/A is_value = TRUE;
2N/A }
2N/A break;
2N/A case CPARATOK:
2N/A /*
2N/A * mark the end of the attribute value
2N/A */
2N/A if (!in_quote)
2N/A is_value = FALSE;
2N/A break;
2N/A case QUOTETOK:
2N/A /*
2N/A * switch on/off the in_quote mode
2N/A */
2N/A in_quote = (in_quote == FALSE);
2N/A break;
2N/A case '\\':
2N/A /*
2N/A * ignore escape characters
2N/A * don't skip if next char is '\0'
2N/A */
2N/A if (!in_quote)
2N/A if (*(++c) == '\0')
2N/A c--;
2N/A break;
2N/A }
2N/A
2N/A }
2N/A
2N/A /*
2N/A * for each valid "=" found, get the name to
2N/A * be mapped
2N/A */
2N/A oc_len = strlen("objectclass");
2N/A for (i = 0; i < num_veq; i++) {
2N/A
2N/A /*
2N/A * look at the left side of "=" to see
2N/A * if assertion is "objectclass=<ocname>"
2N/A * or "<attribute name>=<attribute value>"
2N/A *
2N/A * first skip spaces before "=".
2N/A * Note that filter_c_next may not point to the
2N/A * start of the filter string. For i > 0,
2N/A * it points to the end of the last name processed + 2
2N/A */
2N/A for (tail = info[i]->veq_pos; (tail > filter_c_next) &&
2N/A (*(tail - 1) == SPACETOK); tail--)
2N/A ;
2N/A
2N/A /*
2N/A * mark the end of the left side string (the key)
2N/A */
2N/A *tail = '\0';
2N/A info[i]->name_end = tail - filter_c - 1 + filter;
2N/A
2N/A /*
2N/A * find the start of the key
2N/A */
2N/A key = filter_c_next;
2N/A for (c = tail; filter_c_next <= c; c--) {
2N/A /* OPARATOK is '(' */
2N/A if (*c == OPARATOK ||
2N/A *c == SPACETOK) {
2N/A key = c + 1;
2N/A break;
2N/A }
2N/A }
2N/A info[i]->name_start = key - filter_c + filter;
2N/A
2N/A if ((key + oc_len) <= tail) {
2N/A if (strncasecmp(key, "objectclass",
2N/A oc_len) == 0) {
2N/A /*
2N/A * assertion is "objectclass=ocname",
2N/A * ocname is the one needs to be mapped
2N/A *
2N/A * skip spaces after "=" to find start
2N/A * of the ocname
2N/A */
2N/A head = info[i]->veq_pos;
2N/A for (head = info[i]->veq_pos + 1;
2N/A *head && *head == SPACETOK; head++)
2N/A ;
2N/A
2N/A /* ignore empty ocname */
2N/A if (!(*head))
2N/A continue;
2N/A
2N/A info[i]->name_start = head - filter_c +
2N/A filter;
2N/A
2N/A /*
2N/A * now find the end of the ocname
2N/A */
2N/A for (c = head; ; c++) {
2N/A /* CPARATOK is ')' */
2N/A if (*c == CPARATOK ||
2N/A *c == '\0' ||
2N/A *c == SPACETOK) {
2N/A *c = '\0';
2N/A info[i]->name_end =
2N/A c - filter_c - 1 +
2N/A filter;
2N/A filter_c_next = c + 1;
2N/A info[i]->oc_or_attr = 'o';
2N/A info[i]->from_name = head;
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * assertion is not "objectclass=ocname",
2N/A * assume assertion is "<key> = <value>",
2N/A * <key> is the one needs to be mapped
2N/A */
2N/A if (info[i]->from_name == NULL && strlen(key) > 0) {
2N/A info[i]->oc_or_attr = 'a';
2N/A info[i]->from_name = key;
2N/A }
2N/A }
2N/A
2N/A /* perform schema mapping */
2N/A for (i = 0; i < num_veq; i++) {
2N/A if (info[i]->from_name == NULL)
2N/A continue;
2N/A
2N/A if (info[i]->oc_or_attr == 'a')
2N/A info[i]->mapping =
2N/A __ns_ldap_getMappedAttributes(service,
2N/A info[i]->from_name);
2N/A else
2N/A info[i]->mapping =
2N/A __ns_ldap_getMappedObjectClass(service,
2N/A info[i]->from_name);
2N/A
2N/A if (info[i]->mapping == NULL && auto_service) {
2N/A /*
2N/A * If no mapped attribute/objectclass is found
2N/A * and service == auto*
2N/A * try to find automount's
2N/A * mapped attribute/objectclass
2N/A */
2N/A if (info[i]->oc_or_attr == 'a')
2N/A info[i]->mapping =
2N/A __ns_ldap_getMappedAttributes("automount",
2N/A info[i]->from_name);
2N/A else
2N/A info[i]->mapping =
2N/A __ns_ldap_getMappedObjectClass("automount",
2N/A info[i]->from_name);
2N/A }
2N/A
2N/A if (info[i]->mapping == NULL ||
2N/A info[i]->mapping[0] == NULL) {
2N/A info[i]->to_name = NULL;
2N/A } else if (info[i]->mapping[1] == NULL) {
2N/A info[i]->to_name = info[i]->mapping[0];
2N/A at_least_one = TRUE;
2N/A } else {
2N/A __s_api_free2dArray(info[i]->mapping);
2N/A /*
2N/A * multiple mapping
2N/A * not allowed
2N/A */
2N/A (void) sprintf(errstr,
2N/A gettext(
2N/A "Multiple attribute or objectclass "
2N/A "mapping for '%s' in filter "
2N/A "'%s' not allowed."),
2N/A info[i]->from_name, filter);
2N/A err = strdup(errstr);
2N/A if (err)
2N/A MKERROR(LOG_WARNING, cookie->errorp,
2N/A NS_CONFIG_SYNTAX,
2N/A err, NULL);
2N/A
2N/A free(filter_c);
2N/A for (j = 0; j < num_veq; j++) {
2N/A if (info[j]->mapping)
2N/A __s_api_free2dArray(
2N/A info[j]->mapping);
2N/A free(info[j]);
2N/A }
2N/A free(info);
2N/A return (NS_LDAP_CONFIG);
2N/A }
2N/A }
2N/A
2N/A
2N/A if (at_least_one) {
2N/A
2N/A len = strlen(filter);
2N/A last_copied = filter - 1;
2N/A
2N/A for (i = 0; i < num_veq; i++) {
2N/A if (info[i]->to_name)
2N/A len += strlen(info[i]->to_name);
2N/A }
2N/A
2N/A *new_filter = (char *)calloc(1, len);
2N/A if (*new_filter == NULL) {
2N/A free(filter_c);
2N/A for (j = 0; j < num_veq; j++) {
2N/A if (info[j]->mapping)
2N/A __s_api_free2dArray(
2N/A info[j]->mapping);
2N/A free(info[j]);
2N/A }
2N/A free(info);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A
2N/A for (i = 0; i < num_veq; i++) {
2N/A if (info[i]->to_name != NULL &&
2N/A info[i]->to_name != NULL) {
2N/A
2N/A /*
2N/A * copy the original filter data
2N/A * between the last name and current
2N/A * name
2N/A */
2N/A if ((last_copied + 1) != info[i]->name_start)
2N/A (void) strncat(*new_filter,
2N/A last_copied + 1,
2N/A info[i]->name_start -
2N/A last_copied - 1);
2N/A
2N/A /* the data is copied */
2N/A last_copied = info[i]->name_end;
2N/A
2N/A /*
2N/A * replace the name with
2N/A * the mapped name
2N/A */
2N/A (void) strcat(*new_filter, info[i]->to_name);
2N/A }
2N/A
2N/A /* copy the filter data after the last name */
2N/A if (i == (num_veq -1) &&
2N/A info[i]->name_end <
2N/A (filter + strlen(filter)))
2N/A (void) strncat(*new_filter, last_copied + 1,
2N/A filter + strlen(filter) -
2N/A last_copied - 1);
2N/A }
2N/A
2N/A }
2N/A
2N/A /* free memory */
2N/A free(filter_c);
2N/A for (j = 0; j < num_veq; j++) {
2N/A if (info[j]->mapping)
2N/A __s_api_free2dArray(info[j]->mapping);
2N/A free(info[j]);
2N/A }
2N/A free(info);
2N/A
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/Astatic int
2N/Asetup_next_search(ns_ldap_cookie_t *cookie)
2N/A{
2N/A ns_ldap_search_desc_t *dptr;
2N/A int scope;
2N/A char *filter, *str;
2N/A int baselen;
2N/A int rc;
2N/A void **param;
2N/A
2N/A dptr = *cookie->sdpos;
2N/A scope = cookie->i_flags & (NS_LDAP_SCOPE_BASE |
2N/A NS_LDAP_SCOPE_ONELEVEL |
2N/A NS_LDAP_SCOPE_SUBTREE);
2N/A if (scope)
2N/A cookie->scope = scope;
2N/A else
2N/A cookie->scope = dptr->scope;
2N/A switch (cookie->scope) {
2N/A case NS_LDAP_SCOPE_BASE:
2N/A cookie->scope = LDAP_SCOPE_BASE;
2N/A break;
2N/A case NS_LDAP_SCOPE_ONELEVEL:
2N/A cookie->scope = LDAP_SCOPE_ONELEVEL;
2N/A break;
2N/A case NS_LDAP_SCOPE_SUBTREE:
2N/A cookie->scope = LDAP_SCOPE_SUBTREE;
2N/A break;
2N/A }
2N/A
2N/A filter = NULL;
2N/A if (cookie->use_filtercb && cookie->init_filter_cb &&
2N/A dptr->filter && strlen(dptr->filter) > 0) {
2N/A (*cookie->init_filter_cb)(dptr, &filter,
2N/A cookie->userdata);
2N/A }
2N/A if (filter == NULL) {
2N/A if (cookie->i_filter == NULL) {
2N/A cookie->err_rc = NS_LDAP_INVALID_PARAM;
2N/A return (-1);
2N/A } else {
2N/A if (cookie->filter)
2N/A free(cookie->filter);
2N/A cookie->filter = strdup(cookie->i_filter);
2N/A if (cookie->filter == NULL) {
2N/A cookie->err_rc = NS_LDAP_MEMORY;
2N/A return (-1);
2N/A }
2N/A }
2N/A } else {
2N/A if (cookie->filter)
2N/A free(cookie->filter);
2N/A cookie->filter = strdup(filter);
2N/A free(filter);
2N/A if (cookie->filter == NULL) {
2N/A cookie->err_rc = NS_LDAP_MEMORY;
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * perform attribute/objectclass mapping on filter
2N/A */
2N/A filter = NULL;
2N/A
2N/A if (cookie->service) {
2N/A rc = get_mapped_filter(cookie, &filter);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A cookie->err_rc = rc;
2N/A return (-1);
2N/A } else {
2N/A /*
2N/A * get_mapped_filter returns
2N/A * NULL filter pointer, if
2N/A * no mapping was done
2N/A */
2N/A if (filter) {
2N/A free(cookie->filter);
2N/A cookie->filter = filter;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * validate filter to make sure it's legal
2N/A * [remove redundant ()'s]
2N/A */
2N/A rc = validate_filter(cookie);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A cookie->err_rc = rc;
2N/A return (-1);
2N/A }
2N/A
2N/A baselen = strlen(dptr->basedn);
2N/A if (baselen > 0 && dptr->basedn[baselen-1] == COMMATOK) {
2N/A rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
2N/A (void ***)&param, &cookie->errorp);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A cookie->err_rc = rc;
2N/A return (-1);
2N/A }
2N/A str = ((char **)param)[0];
2N/A baselen += strlen(str)+1;
2N/A if (cookie->basedn)
2N/A free(cookie->basedn);
2N/A cookie->basedn = (char *)malloc(baselen);
2N/A if (cookie->basedn == NULL) {
2N/A cookie->err_rc = NS_LDAP_MEMORY;
2N/A return (-1);
2N/A }
2N/A (void) strcpy(cookie->basedn, dptr->basedn);
2N/A (void) strcat(cookie->basedn, str);
2N/A (void) __ns_ldap_freeParam(&param);
2N/A } else {
2N/A if (cookie->basedn)
2N/A free(cookie->basedn);
2N/A cookie->basedn = strdup(dptr->basedn);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Asetup_referral_search(ns_ldap_cookie_t *cookie)
2N/A{
2N/A ns_ref_info_t *ref_info;
2N/A
2N/A ref_info = cookie->ref_info;
2N/A cookie->scope = ref_info->refScope;
2N/A if (cookie->filter) {
2N/A free(cookie->filter);
2N/A }
2N/A cookie->filter = strdup(ref_info->refFilter);
2N/A if (cookie->basedn) {
2N/A free(cookie->basedn);
2N/A }
2N/A cookie->basedn = strdup(ref_info->refDN);
2N/A if (cookie->filter == NULL || cookie->basedn == NULL) {
2N/A cookie->err_rc = NS_LDAP_MEMORY;
2N/A return (-1);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aget_current_session(ns_ldap_cookie_t *cookie)
2N/A{
2N/A ConnectionID connectionId = -1;
2N/A Connection *conp = NULL;
2N/A int rc;
2N/A int fail_if_new_pwd_reqd = 1;
2N/A
2N/A rc = __s_api_getConnection(NULL, cookie->i_flags,
2N/A cookie->i_auth, &connectionId, &conp,
2N/A &cookie->errorp, fail_if_new_pwd_reqd,
2N/A cookie->nopasswd_acct_mgmt, cookie->conn_user);
2N/A
2N/A /*
2N/A * If password control attached in *cookie->errorp,
2N/A * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
2N/A * free the error structure (we do not need
2N/A * the sec_to_expired info).
2N/A * Reset rc to NS_LDAP_SUCCESS.
2N/A */
2N/A if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
2N/A (void) __ns_ldap_freeError(
2N/A &cookie->errorp);
2N/A cookie->errorp = NULL;
2N/A rc = NS_LDAP_SUCCESS;
2N/A }
2N/A
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A cookie->err_rc = rc;
2N/A return (-1);
2N/A }
2N/A cookie->conn = conp;
2N/A cookie->connectionId = connectionId;
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aget_next_session(ns_ldap_cookie_t *cookie)
2N/A{
2N/A ConnectionID connectionId = -1;
2N/A Connection *conp = NULL;
2N/A int rc;
2N/A int fail_if_new_pwd_reqd = 1;
2N/A
2N/A if (cookie->connectionId > -1) {
2N/A DropConnection(cookie->connectionId, cookie->i_flags);
2N/A cookie->connectionId = -1;
2N/A cookie->conn = NULL;
2N/A }
2N/A
2N/A /*
2N/A * If using an MT connection, return the connection;
2N/A * otherwise, reset the connection user to get ready
2N/A * to use a new connection.
2N/A */
2N/A if (cookie->conn_user != NULL) {
2N/A if (cookie->conn_user->conn_mt != NULL)
2N/A __s_api_conn_mt_return(cookie->conn_user);
2N/A else
2N/A __s_api_conn_user_reset(cookie->conn_user);
2N/A }
2N/A
2N/A rc = __s_api_getConnection(NULL, cookie->i_flags,
2N/A cookie->i_auth, &connectionId, &conp,
2N/A &cookie->errorp, fail_if_new_pwd_reqd,
2N/A cookie->nopasswd_acct_mgmt, cookie->conn_user);
2N/A
2N/A /*
2N/A * If password control attached in *cookie->errorp,
2N/A * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
2N/A * free the error structure (we do not need
2N/A * the sec_to_expired info).
2N/A * Reset rc to NS_LDAP_SUCCESS.
2N/A */
2N/A if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
2N/A (void) __ns_ldap_freeError(
2N/A &cookie->errorp);
2N/A cookie->errorp = NULL;
2N/A rc = NS_LDAP_SUCCESS;
2N/A }
2N/A
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A cookie->err_rc = rc;
2N/A return (-1);
2N/A }
2N/A cookie->conn = conp;
2N/A cookie->connectionId = connectionId;
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Aget_referral_session(ns_ldap_cookie_t *cookie)
2N/A{
2N/A ConnectionID connectionId = -1;
2N/A Connection *conp = NULL;
2N/A int rc;
2N/A int fail_if_new_pwd_reqd = 1;
2N/A ns_ref_info_t *ref_info;
2N/A
2N/A
2N/A if (cookie->connectionId > -1) {
2N/A DropConnection(cookie->connectionId, cookie->i_flags);
2N/A cookie->connectionId = -1;
2N/A cookie->conn = NULL;
2N/A }
2N/A
2N/A /* set it up to use a connection opened for referral */
2N/A if (cookie->conn_user != NULL) {
2N/A /* If using a MT connection, return it. */
2N/A if (cookie->conn_user->conn_mt != NULL)
2N/A __s_api_conn_mt_return(cookie->conn_user);
2N/A cookie->conn_user->referral = B_TRUE;
2N/A }
2N/A
2N/A /* Find a referral ref that works */
2N/A for (ref_info = cookie->referral_pos->ref; ref_info != NULL;
2N/A ref_info = ref_info->next) {
2N/A rc = __s_api_getConnection(ref_info->refHost, 0,
2N/A cookie->i_auth, &connectionId, &conp,
2N/A &cookie->errorp, fail_if_new_pwd_reqd,
2N/A cookie->nopasswd_acct_mgmt, cookie->conn_user);
2N/A if (rc == NS_LDAP_SUCCESS ||
2N/A rc == NS_LDAP_SUCCESS_WITH_INFO) {
2N/A cookie->ref_info = ref_info;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * If password control attached in *cookie->errorp,
2N/A * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
2N/A * free the error structure (we do not need
2N/A * the sec_to_expired info).
2N/A * Reset rc to NS_LDAP_SUCCESS.
2N/A */
2N/A if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
2N/A (void) __ns_ldap_freeError(
2N/A &cookie->errorp);
2N/A cookie->errorp = NULL;
2N/A rc = NS_LDAP_SUCCESS;
2N/A }
2N/A
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A cookie->err_rc = rc;
2N/A return (-1);
2N/A }
2N/A cookie->conn = conp;
2N/A cookie->connectionId = connectionId;
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Apaging_supported(ns_ldap_cookie_t *cookie)
2N/A{
2N/A int rc;
2N/A
2N/A cookie->listType = 0;
2N/A rc = __s_api_isCtrlSupported(cookie->conn,
2N/A LDAP_CONTROL_VLVREQUEST);
2N/A if (rc == NS_LDAP_SUCCESS) {
2N/A cookie->listType = VLVCTRLFLAG;
2N/A return (1);
2N/A }
2N/A rc = __s_api_isCtrlSupported(cookie->conn,
2N/A LDAP_CONTROL_SIMPLE_PAGE);
2N/A if (rc == NS_LDAP_SUCCESS) {
2N/A cookie->listType = SIMPLEPAGECTRLFLAG;
2N/A return (1);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/Atypedef struct servicesorttype {
2N/A char *service;
2N/A ns_srvsidesort_t type;
2N/A} servicesorttype_t;
2N/A
2N/Astatic servicesorttype_t *sort_type = NULL;
2N/Astatic int sort_type_size = 0;
2N/Astatic int sort_type_hwm = 0;
2N/Astatic mutex_t sort_type_mutex = DEFAULTMUTEX;
2N/A
2N/A
2N/Astatic ns_srvsidesort_t
2N/Aget_srvsidesort_type(char *service)
2N/A{
2N/A int i;
2N/A ns_srvsidesort_t type = SSS_UNKNOWN;
2N/A
2N/A if (service == NULL)
2N/A return (type);
2N/A
2N/A (void) mutex_lock(&sort_type_mutex);
2N/A if (sort_type != NULL) {
2N/A for (i = 0; i < sort_type_hwm; i++) {
2N/A if (strcmp(sort_type[i].service, service) == 0) {
2N/A type = sort_type[i].type;
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A (void) mutex_unlock(&sort_type_mutex);
2N/A return (type);
2N/A}
2N/A
2N/Astatic void
2N/Aupdate_srvsidesort_type(char *service, ns_srvsidesort_t type)
2N/A{
2N/A int i, size;
2N/A servicesorttype_t *tmp;
2N/A
2N/A if (service == NULL)
2N/A return;
2N/A
2N/A (void) mutex_lock(&sort_type_mutex);
2N/A
2N/A for (i = 0; i < sort_type_hwm; i++) {
2N/A if (strcmp(sort_type[i].service, service) == 0) {
2N/A sort_type[i].type = type;
2N/A (void) mutex_unlock(&sort_type_mutex);
2N/A return;
2N/A }
2N/A }
2N/A if (sort_type == NULL) {
2N/A size = 10;
2N/A tmp = malloc(size * sizeof (servicesorttype_t));
2N/A if (tmp == NULL) {
2N/A (void) mutex_unlock(&sort_type_mutex);
2N/A return;
2N/A }
2N/A sort_type = tmp;
2N/A sort_type_size = size;
2N/A } else if (sort_type_hwm >= sort_type_size) {
2N/A size = sort_type_size + 10;
2N/A tmp = realloc(sort_type, size * sizeof (servicesorttype_t));
2N/A if (tmp == NULL) {
2N/A (void) mutex_unlock(&sort_type_mutex);
2N/A return;
2N/A }
2N/A sort_type = tmp;
2N/A sort_type_size = size;
2N/A }
2N/A sort_type[sort_type_hwm].service = strdup(service);
2N/A if (sort_type[sort_type_hwm].service == NULL) {
2N/A (void) mutex_unlock(&sort_type_mutex);
2N/A return;
2N/A }
2N/A sort_type[sort_type_hwm].type = type;
2N/A sort_type_hwm++;
2N/A
2N/A (void) mutex_unlock(&sort_type_mutex);
2N/A}
2N/A
2N/Astatic int
2N/Asetup_vlv_params(ns_ldap_cookie_t *cookie)
2N/A{
2N/A LDAPControl **ctrls;
2N/A LDAPsortkey **sortkeylist;
2N/A LDAPControl *sortctrl = NULL;
2N/A LDAPControl *vlvctrl = NULL;
2N/A LDAPVirtualList vlist;
2N/A char *sortattr;
2N/A int rc;
2N/A int free_sort = FALSE;
2N/A
2N/A _freeControlList(&cookie->p_serverctrls);
2N/A
2N/A if (cookie->sortTypeTry == SSS_UNKNOWN)
2N/A cookie->sortTypeTry = get_srvsidesort_type(cookie->service);
2N/A
2N/A if (cookie->sortTypeTry == SSS_UNKNOWN) {
2N/A if (cookie->conn->serverType == NS_LDAP_SERVERTYPE_ODSEE)
2N/A cookie->sortTypeTry = SSS_CN_UID_ATTRS;
2N/A else
2N/A cookie->sortTypeTry = SSS_SINGLE_ATTR;
2N/A }
2N/A
2N/A if (cookie->sortTypeTry == SSS_SINGLE_ATTR) {
2N/A if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
2N/A cookie->i_sortattr) {
2N/A sortattr = __ns_ldap_mapAttribute(cookie->service,
2N/A cookie->i_sortattr);
2N/A free_sort = TRUE;
2N/A } else if (cookie->i_sortattr) {
2N/A sortattr = (char *)cookie->i_sortattr;
2N/A } else {
2N/A sortattr = "cn";
2N/A }
2N/A } else {
2N/A sortattr = "cn uid";
2N/A }
2N/A
2N/A rc = ldap_create_sort_keylist(&sortkeylist, sortattr);
2N/A if (free_sort)
2N/A free(sortattr);
2N/A if (rc != LDAP_SUCCESS) {
2N/A (void) ldap_get_option(cookie->conn->ld,
2N/A LDAP_OPT_ERROR_NUMBER, &rc);
2N/A return (rc);
2N/A }
2N/A rc = ldap_create_sort_control(cookie->conn->ld,
2N/A sortkeylist, 1, &sortctrl);
2N/A ldap_free_sort_keylist(sortkeylist);
2N/A if (rc != LDAP_SUCCESS) {
2N/A (void) ldap_get_option(cookie->conn->ld,
2N/A LDAP_OPT_ERROR_NUMBER, &rc);
2N/A return (rc);
2N/A }
2N/A
2N/A vlist.ldvlist_index = cookie->index;
2N/A vlist.ldvlist_size = 0;
2N/A
2N/A vlist.ldvlist_before_count = 0;
2N/A vlist.ldvlist_after_count = LISTPAGESIZE-1;
2N/A vlist.ldvlist_attrvalue = NULL;
2N/A vlist.ldvlist_extradata = NULL;
2N/A
2N/A rc = ldap_create_virtuallist_control(cookie->conn->ld,
2N/A &vlist, &vlvctrl);
2N/A if (rc != LDAP_SUCCESS) {
2N/A ldap_control_free(sortctrl);
2N/A (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
2N/A &rc);
2N/A return (rc);
2N/A }
2N/A
2N/A ctrls = (LDAPControl **)calloc(3, sizeof (LDAPControl *));
2N/A if (ctrls == NULL) {
2N/A ldap_control_free(sortctrl);
2N/A ldap_control_free(vlvctrl);
2N/A return (LDAP_NO_MEMORY);
2N/A }
2N/A
2N/A ctrls[0] = sortctrl;
2N/A ctrls[1] = vlvctrl;
2N/A
2N/A cookie->p_serverctrls = ctrls;
2N/A return (LDAP_SUCCESS);
2N/A}
2N/A
2N/Astatic int
2N/Asetup_simplepg_params(ns_ldap_cookie_t *cookie)
2N/A{
2N/A LDAPControl **ctrls;
2N/A LDAPControl *pgctrl = NULL;
2N/A int rc;
2N/A
2N/A _freeControlList(&cookie->p_serverctrls);
2N/A
2N/A rc = ldap_create_page_control(cookie->conn->ld, LISTPAGESIZE,
2N/A cookie->ctrlCookie, (char)0, &pgctrl);
2N/A if (rc != LDAP_SUCCESS) {
2N/A (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
2N/A &rc);
2N/A return (rc);
2N/A }
2N/A
2N/A ctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
2N/A if (ctrls == NULL) {
2N/A ldap_control_free(pgctrl);
2N/A return (LDAP_NO_MEMORY);
2N/A }
2N/A ctrls[0] = pgctrl;
2N/A cookie->p_serverctrls = ctrls;
2N/A return (LDAP_SUCCESS);
2N/A}
2N/A
2N/Astatic void
2N/Aproc_result_referrals(ns_ldap_cookie_t *cookie)
2N/A{
2N/A int errCode, rc;
2N/A char **referrals = NULL;
2N/A
2N/A /*
2N/A * Only follow one level of referrals, i.e.
2N/A * if already in referral mode, do nothing
2N/A */
2N/A if (cookie->referral_pos == NULL) {
2N/A cookie->new_state = END_RESULT;
2N/A rc = ldap_parse_result(cookie->conn->ld,
2N/A cookie->resultMsg,
2N/A &errCode, NULL,
2N/A NULL, &referrals,
2N/A NULL, 0);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A (void) ldap_get_option(cookie->conn->ld,
2N/A LDAP_OPT_ERROR_NUMBER,
2N/A &cookie->err_rc);
2N/A cookie->new_state = LDAP_ERROR;
2N/A return;
2N/A }
2N/A if (errCode == LDAP_REFERRAL) {
2N/A /* add to referral list */
2N/A rc = __s_api_addReferral(
2N/A &cookie->referral_list,
2N/A referrals,
2N/A cookie->basedn,
2N/A &cookie->scope,
2N/A cookie->filter,
2N/A cookie->conn->ld);
2N/A if (rc != NS_LDAP_SUCCESS)
2N/A cookie->new_state = ERROR;
2N/A ldap_value_free(referrals);
2N/A }
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aproc_search_references(ns_ldap_cookie_t *cookie)
2N/A{
2N/A char **refurls = NULL;
2N/A int i, rc;
2N/A
2N/A /*
2N/A * Only follow one level of referrals, i.e.
2N/A * if already in referral mode, do nothing
2N/A */
2N/A if (cookie->referral_pos == NULL) {
2N/A refurls = ldap_get_reference_urls(
2N/A cookie->conn->ld,
2N/A cookie->resultMsg);
2N/A if (refurls == NULL) {
2N/A (void) ldap_get_option(cookie->conn->ld,
2N/A LDAP_OPT_ERROR_NUMBER,
2N/A &cookie->err_rc);
2N/A cookie->new_state = LDAP_ERROR;
2N/A return;
2N/A }
2N/A /* add to referral list */
2N/A rc = __s_api_addReferral(
2N/A &cookie->referral_list,
2N/A refurls,
2N/A cookie->basedn,
2N/A &cookie->scope,
2N/A cookie->filter,
2N/A cookie->conn->ld);
2N/A if (rc != NS_LDAP_SUCCESS)
2N/A cookie->new_state = ERROR;
2N/A /* free allocated storage */
2N/A for (i = 0; refurls[i] != NULL; i++)
2N/A free(refurls[i]);
2N/A }
2N/A}
2N/A
2N/Astatic ns_state_t
2N/Amulti_result(ns_ldap_cookie_t *cookie)
2N/A{
2N/A char errstr[MAXERROR];
2N/A char *err;
2N/A ns_ldap_error_t **errorp = NULL;
2N/A LDAPControl **retCtrls = NULL;
2N/A int rc;
2N/A int errCode;
2N/A int finished = 0;
2N/A unsigned long target_posp = 0;
2N/A unsigned long list_size = 0;
2N/A unsigned int count = 0;
2N/A char **referrals = NULL;
2N/A
2N/A if (cookie->listType == VLVCTRLFLAG) {
2N/A rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2N/A &errCode, NULL, NULL, &referrals, &retCtrls, 0);
2N/A if (rc != LDAP_SUCCESS) {
2N/A (void) ldap_get_option(cookie->conn->ld,
2N/A LDAP_OPT_ERROR_NUMBER,
2N/A &cookie->err_rc);
2N/A (void) sprintf(errstr,
2N/A gettext("LDAP ERROR (%d): %s.\n"),
2N/A cookie->err_rc,
2N/A gettext(ldap_err2string(cookie->err_rc)));
2N/A err = strdup(errstr);
2N/A MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2N/A NULL);
2N/A cookie->err_rc = NS_LDAP_INTERNAL;
2N/A cookie->errorp = *errorp;
2N/A return (LDAP_ERROR);
2N/A }
2N/A if (errCode == LDAP_REFERRAL && cookie->followRef) {
2N/A /* add to referral list */
2N/A rc = __s_api_addReferral(
2N/A &cookie->referral_list,
2N/A referrals,
2N/A cookie->basedn,
2N/A &cookie->scope,
2N/A cookie->filter,
2N/A cookie->conn->ld);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A ldap_value_free(referrals);
2N/A if (retCtrls)
2N/A ldap_controls_free(retCtrls);
2N/A return (ERROR);
2N/A }
2N/A ldap_value_free(referrals);
2N/A if (retCtrls)
2N/A ldap_controls_free(retCtrls);
2N/A return (END_RESULT);
2N/A }
2N/A if (referrals) {
2N/A ldap_value_free(referrals);
2N/A referrals = NULL;
2N/A }
2N/A if (retCtrls) {
2N/A rc = ldap_parse_virtuallist_control(
2N/A cookie->conn->ld, retCtrls,
2N/A &target_posp, &list_size, &errCode);
2N/A if (rc == LDAP_SUCCESS) {
2N/A /*
2N/A * AD does not return valid target_posp
2N/A * and list_size
2N/A */
2N/A if (target_posp != 0 && list_size != 0) {
2N/A cookie->index =
2N/A target_posp + LISTPAGESIZE;
2N/A if (cookie->index > list_size)
2N/A finished = 1;
2N/A } else {
2N/A if (cookie->entryCount < LISTPAGESIZE)
2N/A finished = 1;
2N/A else
2N/A cookie->index +=
2N/A cookie->entryCount;
2N/A }
2N/A }
2N/A ldap_controls_free(retCtrls);
2N/A retCtrls = NULL;
2N/A }
2N/A else
2N/A finished = 1;
2N/A } else if (cookie->listType == SIMPLEPAGECTRLFLAG) {
2N/A rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2N/A &errCode, NULL, NULL, &referrals, &retCtrls, 0);
2N/A if (rc != LDAP_SUCCESS) {
2N/A (void) ldap_get_option(cookie->conn->ld,
2N/A LDAP_OPT_ERROR_NUMBER,
2N/A &cookie->err_rc);
2N/A (void) sprintf(errstr,
2N/A gettext("LDAP ERROR (%d): %s.\n"),
2N/A cookie->err_rc,
2N/A gettext(ldap_err2string(cookie->err_rc)));
2N/A err = strdup(errstr);
2N/A MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2N/A NULL);
2N/A cookie->err_rc = NS_LDAP_INTERNAL;
2N/A cookie->errorp = *errorp;
2N/A return (LDAP_ERROR);
2N/A }
2N/A if (errCode == LDAP_REFERRAL && cookie->followRef) {
2N/A /* add to referral list */
2N/A rc = __s_api_addReferral(
2N/A &cookie->referral_list,
2N/A referrals,
2N/A cookie->basedn,
2N/A &cookie->scope,
2N/A cookie->filter,
2N/A cookie->conn->ld);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A ldap_value_free(referrals);
2N/A if (retCtrls)
2N/A ldap_controls_free(retCtrls);
2N/A return (ERROR);
2N/A }
2N/A ldap_value_free(referrals);
2N/A if (retCtrls)
2N/A ldap_controls_free(retCtrls);
2N/A return (END_RESULT);
2N/A }
2N/A if (referrals) {
2N/A ldap_value_free(referrals);
2N/A referrals = NULL;
2N/A }
2N/A if (retCtrls) {
2N/A if (cookie->ctrlCookie)
2N/A ber_bvfree(cookie->ctrlCookie);
2N/A cookie->ctrlCookie = NULL;
2N/A rc = ldap_parse_page_control(
2N/A cookie->conn->ld, retCtrls,
2N/A &count, &cookie->ctrlCookie);
2N/A if (rc == LDAP_SUCCESS) {
2N/A if ((cookie->ctrlCookie == NULL) ||
2N/A (cookie->ctrlCookie->bv_val == NULL) ||
2N/A (cookie->ctrlCookie->bv_len == 0))
2N/A finished = 1;
2N/A }
2N/A ldap_controls_free(retCtrls);
2N/A retCtrls = NULL;
2N/A }
2N/A else
2N/A finished = 1;
2N/A }
2N/A if (!finished && cookie->listType == VLVCTRLFLAG)
2N/A return (NEXT_VLV);
2N/A if (!finished && cookie->listType == SIMPLEPAGECTRLFLAG)
2N/A return (NEXT_PAGE);
2N/A if (finished)
2N/A return (END_RESULT);
2N/A return (ERROR);
2N/A}
2N/A
2N/A/*
2N/A * clear_results(ns_ldap_cookie_t):
2N/A *
2N/A * Attempt to obtain remnants of ldap responses and free them. If remnants are
2N/A * not obtained within a certain time period tell the server we wish to abandon
2N/A * the request.
2N/A *
2N/A * Note that we do not initially tell the server to abandon the request as that
2N/A * can be an expensive operation for the server, while it is cheap for us to
2N/A * just flush the input.
2N/A *
2N/A * If something was to remain in libldap queue as a result of some error then
2N/A * it would be freed later during drop connection call or when no other
2N/A * requests share the connection.
2N/A */
2N/Astatic void
2N/Aclear_results(ns_ldap_cookie_t *cookie)
2N/A{
2N/A int rc;
2N/A if (cookie->conn != NULL && cookie->conn->ld != NULL &&
2N/A (cookie->connectionId != -1 ||
2N/A (cookie->conn_user != NULL &&
2N/A cookie->conn_user->conn_mt != NULL)) &&
2N/A cookie->msgId != 0) {
2N/A /*
2N/A * We need to cleanup the rest of response (if there is such)
2N/A * and LDAP abandon is too heavy for LDAP servers, so we will
2N/A * wait for the rest of response till timeout and "process" it.
2N/A */
2N/A if (cookie->conn_user != NULL && cookie->conn_user->use_mt_conn)
2N/A rc = __s_api_getLdapResult(cookie->conn->ld,
2N/A cookie->msgId, LDAP_MSG_ALL,
2N/A &cookie->search_timeout, &cookie->resultMsg);
2N/A else
2N/A rc = ldap_result(cookie->conn->ld, cookie->msgId,
2N/A LDAP_MSG_ALL, &cookie->search_timeout,
2N/A &cookie->resultMsg);
2N/A
2N/A if (rc != -1 && rc != 0 && cookie->resultMsg != NULL) {
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A }
2N/A
2N/A /*
2N/A * If there was timeout then we will send ABANDON request to
2N/A * LDAP server to decrease load.
2N/A */
2N/A if (rc == 0)
2N/A (void) ldap_abandon_ext(cookie->conn->ld, cookie->msgId,
2N/A NULL, NULL);
2N/A /* Disassociate cookie with msgId */
2N/A cookie->msgId = 0;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * This state machine performs one or more LDAP searches to a given
2N/A * directory server using service search descriptors and schema
2N/A * mapping as appropriate. The approximate pseudocode for
2N/A * this routine is the following:
2N/A * Given the current configuration [set/reset connection etc.]
2N/A * and the current service search descriptor list
2N/A * or default search filter parameters
2N/A * foreach (service search filter) {
2N/A * initialize the filter [via filter_init if appropriate]
2N/A * get a valid session/connection (preferably the current one)
2N/A * Recover if the connection is lost
2N/A * perform the search
2N/A * foreach (result entry) {
2N/A * process result [via callback if appropriate]
2N/A * save result for caller if accepted.
2N/A * exit and return all collected if allResults found;
2N/A * }
2N/A * }
2N/A * return collected results and exit
2N/A */
2N/A
2N/Astatic
2N/Ans_state_t
2N/Asearch_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
2N/A{
2N/A char errstr[MAXERROR];
2N/A char *err;
2N/A int rc;
2N/A int ldap_res_rc;
2N/A ns_ldap_entry_t *nextEntry;
2N/A ns_ldap_error_t *error = NULL;
2N/A ns_ldap_error_t **errorp;
2N/A struct timeval tv;
2N/A char *basedn_save = NULL;
2N/A int scope_save = NS_LDAP_SCOPE_ONELEVEL;
2N/A char *filter_save = NULL;
2N/A char **attrs_save = NULL;
2N/A int msgId_save = 0;
2N/A ns_state_t state_save = NEXT_RESULT;
2N/A LDAPControl **p_serverctrls_save = NULL;
2N/A
2N/A errorp = &error;
2N/A cookie->state = state;
2N/A errstr[0] = '\0';
2N/A
2N/A for (;;) {
2N/A switch (cookie->state) {
2N/A case CLEAR_RESULTS:
2N/A clear_results(cookie);
2N/A cookie->new_state = EXIT;
2N/A break;
2N/A case GET_ACCT_MGMT_INFO:
2N/A /*
2N/A * Set the flag to get ldap account management controls.
2N/A */
2N/A cookie->nopasswd_acct_mgmt = 1;
2N/A cookie->new_state = INIT;
2N/A break;
2N/A case EXIT:
2N/A /* state engine/connection cleaned up in delete */
2N/A if (cookie->attribute) {
2N/A __s_api_free2dArray(cookie->attribute);
2N/A cookie->attribute = NULL;
2N/A }
2N/A if (cookie->referral_list) {
2N/A __s_api_deleteReferral(cookie->referral_list);
2N/A cookie->referral_list = NULL;
2N/A }
2N/A return (EXIT);
2N/A case INIT:
2N/A cookie->sdpos = NULL;
2N/A cookie->new_state = NEXT_SEARCH_DESCRIPTOR;
2N/A if (cookie->attribute) {
2N/A __s_api_free2dArray(cookie->attribute);
2N/A cookie->attribute = NULL;
2N/A }
2N/A if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
2N/A cookie->i_attr) {
2N/A cookie->attribute =
2N/A __ns_ldap_mapAttributeList(
2N/A cookie->service,
2N/A cookie->i_attr);
2N/A }
2N/A break;
2N/A case REINIT:
2N/A /* Check if we've reached MAX retries. */
2N/A cookie->retries++;
2N/A if (cookie->retries > NS_LIST_TRY_MAX - 1) {
2N/A cookie->new_state = LDAP_ERROR;
2N/A break;
2N/A }
2N/A
2N/A /*
2N/A * Even if we still have retries left, check
2N/A * if retry is possible.
2N/A */
2N/A if (cookie->conn_user != NULL) {
2N/A int retry;
2N/A ns_conn_mgmt_t *cmg;
2N/A cmg = cookie->conn_user->conn_mgmt;
2N/A retry = cookie->conn_user->retry;
2N/A if (cmg != NULL && cmg->cfg_reloaded == 1)
2N/A retry = 1;
2N/A if (retry == 0) {
2N/A cookie->new_state = LDAP_ERROR;
2N/A break;
2N/A }
2N/A }
2N/A /*
2N/A * Free results if any, reset to the first
2N/A * search descriptor and start a new session.
2N/A */
2N/A if (cookie->resultMsg != NULL) {
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A }
2N/A (void) __ns_ldap_freeError(&cookie->errorp);
2N/A (void) __ns_ldap_freeResult(&cookie->result);
2N/A (void) __ns_ldap_freeEntry(cookie->extra_info);
2N/A cookie->extra_info = NULL;
2N/A cookie->sdpos = cookie->sdlist;
2N/A cookie->err_from_result = 0;
2N/A cookie->err_rc = 0;
2N/A cookie->new_state = NEXT_SESSION;
2N/A break;
2N/A case NEXT_SEARCH_DESCRIPTOR:
2N/A /* get next search descriptor */
2N/A if (cookie->sdpos == NULL) {
2N/A cookie->sdpos = cookie->sdlist;
2N/A cookie->new_state = GET_SESSION;
2N/A } else {
2N/A cookie->sdpos++;
2N/A cookie->new_state = NEXT_SEARCH;
2N/A }
2N/A if (*cookie->sdpos == NULL)
2N/A cookie->new_state = EXIT;
2N/A break;
2N/A case GET_SESSION:
2N/A if (get_current_session(cookie) < 0)
2N/A cookie->new_state = NEXT_SESSION;
2N/A else
2N/A cookie->new_state = NEXT_SEARCH;
2N/A break;
2N/A case NEXT_SESSION:
2N/A if (get_next_session(cookie) < 0)
2N/A cookie->new_state = RESTART_SESSION;
2N/A else
2N/A cookie->new_state = NEXT_SEARCH;
2N/A break;
2N/A /*
2N/A * This state drops the current session/connection because
2N/A * error occurred when using the connection. On entry,
2N/A * cookie->err_rc must be set to the ldap error code,
2N/A * on exit, cookie->new_state will be set to the next
2N/A * state to go, LDAP_ERROR, REINIT, or NEXT_SESSION.
2N/A */
2N/A case DROP_SESSION:
2N/A /* Close the connection, if a shared one */
2N/A if (cookie->conn_user != NULL) {
2N/A ns_ldap_error_t *errorp = NULL;
2N/A
2N/A /* retry if allowed */
2N/A cookie->conn_user->retry = B_TRUE;
2N/A if (cookie->conn_user->conn_mt != NULL) {
2N/A /* Shared connection, close it. */
2N/A __s_api_conn_mt_close(cookie->conn_user,
2N/A cookie->err_rc, &errorp);
2N/A if (errorp != NULL) {
2N/A (void) __ns_ldap_freeError(
2N/A &cookie->errorp);
2N/A cookie->errorp = errorp;
2N/A cookie->new_state = LDAP_ERROR;
2N/A }
2N/A }
2N/A }
2N/A if (cookie->connectionId > -1) {
2N/A /*
2N/A * Remove the server from ldap_cachemgr's list,
2N/A * if rc is not LDAP_SERVER_DOWN. We assume
2N/A * LDAP SERVER_DOWN is due to idle timeout or
2N/A * clean server shutdown, so reconnect should
2N/A * be tried next.
2N/A */
2N/A if (cookie->err_rc != LDAP_SERVER_DOWN)
2N/A (void) __s_api_removeServer(
2N/A cookie->conn->serverAddr);
2N/A /*
2N/A * NS_LDAP_NEW_CONN indicates that the
2N/A * connection should be deleted, not
2N/A * kept alive
2N/A */
2N/A DropConnection(cookie->connectionId,
2N/A NS_LDAP_NEW_CONN);
2N/A cookie->connectionId = -1;
2N/A cookie->conn = NULL;
2N/A }
2N/A cookie->new_state = cookie->next_state;
2N/A break;
2N/A case RESTART_SESSION:
2N/A if (cookie->i_flags & NS_LDAP_HARD) {
2N/A cookie->new_state = NEXT_SESSION;
2N/A break;
2N/A }
2N/A (void) sprintf(errstr,
2N/A gettext("Session error no available conn.\n"),
2N/A state);
2N/A err = strdup(errstr);
2N/A MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2N/A NULL);
2N/A cookie->err_rc = NS_LDAP_INTERNAL;
2N/A cookie->errorp = *errorp;
2N/A cookie->new_state = EXIT;
2N/A break;
2N/A case NEXT_SEARCH:
2N/A /* setup referrals search if necessary */
2N/A if (cookie->referral_pos) {
2N/A if (setup_referral_search(cookie) < 0) {
2N/A cookie->new_state = EXIT;
2N/A break;
2N/A }
2N/A } else if (setup_next_search(cookie) < 0) {
2N/A cookie->new_state = EXIT;
2N/A break;
2N/A }
2N/A /* only do VLV/PAGE on scopes onelevel/subtree */
2N/A if (paging_supported(cookie)) {
2N/A if (cookie->use_paging &&
2N/A (cookie->scope != LDAP_SCOPE_BASE)) {
2N/A cookie->index = 1;
2N/A if (cookie->listType == VLVCTRLFLAG)
2N/A cookie->new_state = NEXT_VLV;
2N/A else
2N/A cookie->new_state = NEXT_PAGE;
2N/A break;
2N/A }
2N/A }
2N/A cookie->new_state = ONE_SEARCH;
2N/A break;
2N/A case NEXT_VLV:
2N/A rc = setup_vlv_params(cookie);
2N/A if (rc != LDAP_SUCCESS) {
2N/A cookie->err_rc = rc;
2N/A cookie->new_state = LDAP_ERROR;
2N/A break;
2N/A }
2N/A cookie->next_state = MULTI_RESULT;
2N/A cookie->new_state = DO_SEARCH;
2N/A break;
2N/A case NEXT_PAGE:
2N/A rc = setup_simplepg_params(cookie);
2N/A if (rc != LDAP_SUCCESS) {
2N/A cookie->err_rc = rc;
2N/A cookie->new_state = LDAP_ERROR;
2N/A break;
2N/A }
2N/A cookie->next_state = MULTI_RESULT;
2N/A cookie->new_state = DO_SEARCH;
2N/A break;
2N/A case ONE_SEARCH:
2N/A cookie->next_state = NEXT_RESULT;
2N/A cookie->new_state = DO_SEARCH;
2N/A break;
2N/A case NEXT_RANGE:
2N/A /*
2N/A * Do search if more range of values to get.
2N/A * Otherwise, restore search related data in
2N/A * cookie and go to the NEXT_RESULT state to
2N/A * remove the last LDAP_RES_SEARCH_RESULT
2N/A * of this range search and have the result
2N/A * processed.
2N/A */
2N/A if (cookie->range_info == NULL) {
2N/A cookie->basedn = basedn_save;
2N/A cookie->scope = scope_save;
2N/A cookie->filter = filter_save;
2N/A cookie->attribute = attrs_save;
2N/A cookie->p_serverctrls = p_serverctrls_save;
2N/A
2N/A basedn_save = NULL;
2N/A filter_save = NULL;
2N/A attrs_save = NULL;
2N/A p_serverctrls_save = NULL;
2N/A
2N/A cookie->new_state = NEXT_RESULT;
2N/A break;
2N/A }
2N/A
2N/A /*
2N/A * Change/save the search related data in cookie to
2N/A * get the next range of values.
2N/A */
2N/A if (basedn_save == NULL) {
2N/A basedn_save = cookie->basedn;
2N/A scope_save = cookie->scope;
2N/A filter_save = cookie->filter;
2N/A attrs_save = cookie->attribute;
2N/A msgId_save = cookie->msgId;
2N/A p_serverctrls_save = cookie->p_serverctrls;
2N/A
2N/A cookie->basedn = cookie->range_info->dn;
2N/A cookie->scope = LDAP_SCOPE_BASE;
2N/A cookie->filter = "(objectclass=*)";
2N/A cookie->msgId = 0;
2N/A cookie->p_serverctrls = NULL;
2N/A }
2N/A cookie->attribute = cookie->range_info->attr_to_search;
2N/A
2N/A cookie->new_state = DO_SEARCH;
2N/A cookie->next_state = NEXT_RESULT;
2N/A
2N/A break;
2N/A case DO_SEARCH:
2N/A if (!cookie->get_next_range)
2N/A cookie->entryCount = 0;
2N/A rc = ldap_search_ext(cookie->conn->ld,
2N/A cookie->basedn,
2N/A cookie->scope,
2N/A cookie->filter,
2N/A cookie->attribute,
2N/A 0,
2N/A cookie->p_serverctrls,
2N/A NULL,
2N/A &cookie->search_timeout, 0,
2N/A &cookie->msgId);
2N/A if (rc == LDAP_SUCCESS) {
2N/A cookie->new_state = cookie->next_state;
2N/A break;
2N/A }
2N/A
2N/A cookie->err_rc = rc;
2N/A
2N/A /* Server no good, may need to unwind request & retry */
2N/A if (rc == LDAP_CONNECT_ERROR ||
2N/A rc == LDAP_SERVER_DOWN ||
2N/A rc == LDAP_TIMEOUT) {
2N/A cookie->new_state = DROP_SESSION;
2N/A cookie->next_state = LDAP_ERROR;
2N/A }
2N/A
2N/A if (rc == LDAP_BUSY ||
2N/A rc == LDAP_UNAVAILABLE ||
2N/A rc == LDAP_UNWILLING_TO_PERFORM ||
2N/A rc == LDAP_CONNECT_ERROR ||
2N/A rc == LDAP_SERVER_DOWN ||
2N/A rc == LDAP_TIMEOUT) {
2N/A /*
2N/A * drop session then reinit
2N/A */
2N/A if (cookie->reinit_on_retriable_err) {
2N/A cookie->new_state = DROP_SESSION;
2N/A cookie->next_state = REINIT;
2N/A break;
2N/A } else if (cookie->result == NULL) {
2N/A /*
2N/A * Redo the search in
2N/A * next session only if
2N/A * it was the first search,
2N/A * i.e., no result entries
2N/A * saved in the cookie.
2N/A */
2N/A if (cookie->new_state != DROP_SESSION) {
2N/A /*
2N/A * no drop session, just get
2N/A * next session
2N/A */
2N/A cookie->new_state =
2N/A NEXT_SESSION;
2N/A } else {
2N/A /*
2N/A * Drop session then get
2N/A * next session. New state
2N/A * is already DROP_SESSION.
2N/A */
2N/A cookie->next_state =
2N/A NEXT_SESSION;
2N/A }
2N/A cookie->err_rc = NS_LDAP_SUCCESS;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (cookie->new_state != DROP_SESSION)
2N/A cookie->new_state = LDAP_ERROR;
2N/A break;
2N/A case NEXT_RANGE_RESULT:
2N/A /*
2N/A * If all range of attribute values
2N/A * have been retrieved, go back to
2N/A * normal result processing. Otherwise,
2N/A * get the next range.
2N/A */
2N/A if (cookie->range_info != NULL) {
2N/A cookie->new_state = NEXT_RANGE;
2N/A break;
2N/A }
2N/A
2N/A cookie->new_state = PROCESS_RESULT;
2N/A cookie->next_state = state_save;
2N/A cookie->msgId = msgId_save;
2N/A msgId_save = 0;
2N/A cookie->get_next_range = B_FALSE;
2N/A rc = 0;
2N/A break;
2N/A
2N/A /*
2N/A * RESULT_ERROR expects the return code from ldap_result()
2N/A * be saved in cookie->err_rc. The ldap result rc is
2N/A * converted to ldap error code to see if it's a retry-able
2N/A * error, if so, go to REINIT or NEXT_SESSION to retry.
2N/A * Otherwise, go to DROP_SESSION then return to LDAP_ERROR
2N/A * to exit the state machine.
2N/A */
2N/A case RESULT_ERROR:
2N/A switch (cookie->err_rc) {
2N/A case 0:
2N/A rc = LDAP_TIMEOUT;
2N/A break;
2N/A case -1:
2N/A rc = ldap_get_lderrno(cookie->conn->ld,
2N/A NULL, NULL);
2N/A break;
2N/A default:
2N/A rc = ldap_result2error(cookie->conn->ld,
2N/A cookie->resultMsg, 1);
2N/A break;
2N/A }
2N/A
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A cookie->err_from_result = 1;
2N/A cookie->err_rc = rc;
2N/A
2N/A /* retryable error */
2N/A if (rc == LDAP_BUSY ||
2N/A rc == LDAP_UNAVAILABLE ||
2N/A rc == LDAP_UNWILLING_TO_PERFORM) {
2N/A if (cookie->reinit_on_retriable_err) {
2N/A cookie->new_state = REINIT;
2N/A break;
2N/A } else if (cookie->result == NULL) {
2N/A cookie->err_from_result = 0;
2N/A cookie->err_rc =
2N/A NS_LDAP_SUCCESS;
2N/A cookie->new_state =
2N/A NEXT_SESSION;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Server no good, may need to unwind
2N/A * request & retry
2N/A */
2N/A if (rc == LDAP_CONNECT_ERROR ||
2N/A rc == LDAP_SERVER_DOWN ||
2N/A rc == LDAP_TIMEOUT) {
2N/A cookie->new_state = DROP_SESSION;
2N/A if (cookie->reinit_on_retriable_err)
2N/A cookie->next_state = REINIT;
2N/A else
2N/A cookie->next_state = LDAP_ERROR;
2N/A
2N/A } else
2N/A cookie->new_state = LDAP_ERROR;
2N/A break;
2N/A case NEXT_RESULT:
2N/A /*
2N/A * Caller (e.g. __ns_ldap_list_batch_add)
2N/A * does not want to block on ldap_result().
2N/A * Therefore we execute ldap_result() with
2N/A * a zeroed timeval.
2N/A */
2N/A if (cookie->no_wait == B_TRUE)
2N/A (void) memset(&tv, 0, sizeof (tv));
2N/A else
2N/A tv = cookie->search_timeout;
2N/A
2N/A if (cookie->conn_user != NULL &&
2N/A cookie->conn_user->use_mt_conn)
2N/A ldap_res_rc = __s_api_getLdapResult(
2N/A cookie->conn->ld, cookie->msgId,
2N/A LDAP_MSG_ONE, &tv, &cookie->resultMsg);
2N/A else
2N/A ldap_res_rc = ldap_result(cookie->conn->ld,
2N/A cookie->msgId, LDAP_MSG_ONE, &tv,
2N/A &cookie->resultMsg);
2N/A
2N/A if (ldap_res_rc == LDAP_RES_SEARCH_RESULT) {
2N/A if (cookie->get_next_range) {
2N/A cookie->new_state = NEXT_RANGE_RESULT;
2N/A } else {
2N/A cookie->new_state = END_RESULT;
2N/A /* check and process referrals info */
2N/A if (cookie->followRef)
2N/A proc_result_referrals(cookie);
2N/A }
2N/A
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A break;
2N/A }
2N/A /* handle referrals if necessary */
2N/A if (ldap_res_rc == LDAP_RES_SEARCH_REFERENCE) {
2N/A if (cookie->followRef)
2N/A proc_search_references(cookie);
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A break;
2N/A }
2N/A if (ldap_res_rc != LDAP_RES_SEARCH_ENTRY) {
2N/A if (ldap_res_rc == 0 && cookie->no_wait) {
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A return (cookie->new_state);
2N/A }
2N/A cookie->err_rc = ldap_res_rc;
2N/A cookie->new_state = RESULT_ERROR;
2N/A break;
2N/A }
2N/A /* else LDAP_RES_SEARCH_ENTRY */
2N/A /* get account management response control */
2N/A if (cookie->nopasswd_acct_mgmt == 1) {
2N/A rc = ldap_get_entry_controls(cookie->conn->ld,
2N/A cookie->resultMsg,
2N/A &(cookie->resultctrl));
2N/A if (rc != LDAP_SUCCESS) {
2N/A cookie->new_state = LDAP_ERROR;
2N/A cookie->err_rc = rc;
2N/A break;
2N/A }
2N/A }
2N/A rc = __s_api_getEntry(cookie);
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A cookie->new_state = LDAP_ERROR;
2N/A break;
2N/A }
2N/A
2N/A /*
2N/A * If not all values of certain attributes,
2N/A * such as member or memberof, are returned,
2N/A * as indicated by the 'range' option attached
2N/A * to the attribute type, then search the
2N/A * same DN entry again to get the entire
2N/A * range of the attribute values. If this
2N/A * is not the first such search, then go
2N/A * to the NEXT_RESULT state to remove the
2N/A * remaining LDAP_RES_SEARCH_RESULT from the
2N/A * result message to prevent memory leaks.
2N/A */
2N/A if (cookie->get_next_range) {
2N/A cookie->new_state = NEXT_RANGE;
2N/A state_save = cookie->state;
2N/A break;
2N/A }
2N/A
2N/A cookie->new_state = PROCESS_RESULT;
2N/A cookie->next_state = NEXT_RESULT;
2N/A break;
2N/A case MULTI_RESULT:
2N/A if (cookie->no_wait == B_TRUE)
2N/A (void) memset(&tv, 0, sizeof (tv));
2N/A else
2N/A tv = cookie->search_timeout;
2N/A
2N/A if (cookie->conn_user != NULL &&
2N/A cookie->conn_user->use_mt_conn)
2N/A ldap_res_rc = __s_api_getLdapResult(
2N/A cookie->conn->ld, cookie->msgId,
2N/A LDAP_MSG_ONE, &tv, &cookie->resultMsg);
2N/A else
2N/A ldap_res_rc = ldap_result(cookie->conn->ld,
2N/A cookie->msgId, LDAP_MSG_ONE, &tv,
2N/A &cookie->resultMsg);
2N/A
2N/A if (ldap_res_rc == LDAP_RES_SEARCH_RESULT) {
2N/A rc = ldap_result2error(cookie->conn->ld,
2N/A cookie->resultMsg, 0);
2N/A if (rc == LDAP_ADMINLIMIT_EXCEEDED &&
2N/A cookie->listType == VLVCTRLFLAG &&
2N/A cookie->sortTypeTry == SSS_SINGLE_ATTR) {
2N/A /* Try old "cn uid" server side sort */
2N/A cookie->sortTypeTry = SSS_CN_UID_ATTRS;
2N/A cookie->new_state = NEXT_VLV;
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A break;
2N/A }
2N/A if (rc != LDAP_SUCCESS && rc != LDAP_REFERRAL) {
2N/A cookie->err_rc = rc;
2N/A cookie->new_state = LDAP_ERROR;
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A break;
2N/A }
2N/A cookie->new_state = multi_result(cookie);
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A break;
2N/A }
2N/A /* handle referrals if necessary */
2N/A if (ldap_res_rc == LDAP_RES_SEARCH_REFERENCE) {
2N/A if (cookie->followRef)
2N/A proc_search_references(cookie);
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A break;
2N/A }
2N/A if (ldap_res_rc != LDAP_RES_SEARCH_ENTRY) {
2N/A if (ldap_res_rc == 0 && cookie->no_wait) {
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A return (cookie->new_state);
2N/A }
2N/A cookie->err_rc = ldap_res_rc;
2N/A cookie->new_state = RESULT_ERROR;
2N/A break;
2N/A }
2N/A /* else LDAP_RES_SEARCH_ENTRY */
2N/A cookie->entryCount++;
2N/A rc = __s_api_getEntry(cookie);
2N/A (void) ldap_msgfree(cookie->resultMsg);
2N/A cookie->resultMsg = NULL;
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A cookie->new_state = LDAP_ERROR;
2N/A break;
2N/A }
2N/A /*
2N/A * If VLV search was successfull save the server
2N/A * side sort type tried.
2N/A */
2N/A if (cookie->listType == VLVCTRLFLAG)
2N/A update_srvsidesort_type(cookie->service,
2N/A cookie->sortTypeTry);
2N/A
2N/A /*
2N/A * If not all values of certain attributes,
2N/A * such as member or memberof, are returned,
2N/A * as indicated by the 'range' option attached
2N/A * to the attribute type, then search the
2N/A * same entry again to get the rest of the
2N/A * attribute values.
2N/A */
2N/A if (cookie->range_info != NULL) {
2N/A cookie->new_state = NEXT_RANGE;
2N/A state_save = cookie->state;
2N/A break;
2N/A }
2N/A
2N/A cookie->new_state = PROCESS_RESULT;
2N/A cookie->next_state = MULTI_RESULT;
2N/A break;
2N/A case PROCESS_RESULT:
2N/A /* NOTE THIS STATE MAY BE PROCESSED BY CALLER */
2N/A if (cookie->use_usercb && cookie->callback) {
2N/A rc = 0;
2N/A for (nextEntry = cookie->result->entry;
2N/A nextEntry != NULL;
2N/A nextEntry = nextEntry->next) {
2N/A rc = (*cookie->callback)(nextEntry,
2N/A cookie->userdata);
2N/A
2N/A if (rc == NS_LDAP_CB_DONE) {
2N/A /* cb doesn't want any more data */
2N/A rc = NS_LDAP_PARTIAL;
2N/A cookie->err_rc = rc;
2N/A break;
2N/A } else if (rc != NS_LDAP_CB_NEXT) {
2N/A /* invalid return code */
2N/A rc = NS_LDAP_OP_FAILED;
2N/A cookie->err_rc = rc;
2N/A break;
2N/A }
2N/A }
2N/A (void) __ns_ldap_freeResult(&cookie->result);
2N/A cookie->result = NULL;
2N/A if (cookie->extra_info != NULL)
2N/A __ns_ldap_freeEntry(cookie->extra_info);
2N/A cookie->extra_info = NULL;
2N/A }
2N/A if (rc != 0) {
2N/A cookie->new_state = EXIT;
2N/A break;
2N/A }
2N/A /* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */
2N/A cookie->new_state = cookie->next_state;
2N/A break;
2N/A case END_PROCESS_RESULT:
2N/A cookie->new_state = cookie->next_state;
2N/A break;
2N/A case END_RESULT:
2N/A /*
2N/A * XXX DO WE NEED THIS CASE?
2N/A * if (search is complete) {
2N/A * cookie->new_state = EXIT;
2N/A * } else
2N/A */
2N/A /*
2N/A * entering referral mode if necessary
2N/A */
2N/A if (cookie->followRef && cookie->referral_list)
2N/A cookie->new_state =
2N/A NEXT_REFERRAL;
2N/A else
2N/A cookie->new_state =
2N/A NEXT_SEARCH_DESCRIPTOR;
2N/A break;
2N/A case NEXT_REFERRAL:
2N/A /* get next referral info */
2N/A if (cookie->referral_pos == NULL)
2N/A cookie->referral_pos =
2N/A cookie->referral_list;
2N/A else
2N/A cookie->referral_pos =
2N/A cookie->referral_pos->next;
2N/A /* check see if done with all referrals */
2N/A if (cookie->referral_pos != NULL)
2N/A cookie->new_state =
2N/A GET_REFERRAL_SESSION;
2N/A else {
2N/A __s_api_deleteReferral(cookie->referral_list);
2N/A cookie->referral_list = NULL;
2N/A cookie->new_state =
2N/A NEXT_SEARCH_DESCRIPTOR;
2N/A if (cookie->conn_user != NULL)
2N/A cookie->conn_user->referral = B_FALSE;
2N/A }
2N/A break;
2N/A case GET_REFERRAL_SESSION:
2N/A if (get_referral_session(cookie) < 0)
2N/A cookie->new_state = EXIT;
2N/A else {
2N/A cookie->new_state = NEXT_SEARCH;
2N/A }
2N/A break;
2N/A case NEXT_RANGE_RESTORE:
2N/A if (cookie->range_info == NULL) {
2N/A cookie->new_state = cookie->next_state;
2N/A break;
2N/A }
2N/A
2N/A cookie->basedn = basedn_save;
2N/A cookie->scope = scope_save;
2N/A cookie->filter = filter_save;
2N/A cookie->attribute = attrs_save;
2N/A cookie->p_serverctrls = p_serverctrls_save;
2N/A if (msgId_save != 0)
2N/A cookie->msgId = msgId_save;
2N/A
2N/A basedn_save = NULL;
2N/A filter_save = NULL;
2N/A attrs_save = NULL;
2N/A p_serverctrls_save = NULL;
2N/A if (cookie->range_info != NULL)
2N/A free_range_info(&cookie->range_info);
2N/A
2N/A cookie->new_state = cookie->next_state;
2N/A break;
2N/A case LDAP_ERROR:
2N/A if (cookie->range_info != NULL) {
2N/A cookie->new_state = NEXT_RANGE_RESTORE;
2N/A cookie->next_state = LDAP_ERROR;
2N/A break;
2N/A }
2N/A
2N/A if (cookie->err_from_result) {
2N/A if (cookie->err_rc == LDAP_SERVER_DOWN) {
2N/A (void) sprintf(errstr,
2N/A gettext("LDAP ERROR (%d): "
2N/A "Error occurred during"
2N/A " receiving results. "
2N/A "Connection to server lost."),
2N/A cookie->err_rc);
2N/A } else {
2N/A (void) sprintf(errstr,
2N/A gettext("LDAP ERROR (%d): "
2N/A "Error occurred during"
2N/A " receiving results. %s"
2N/A "."), cookie->err_rc,
2N/A ldap_err2string(
2N/A cookie->err_rc));
2N/A }
2N/A } else
2N/A (void) sprintf(errstr,
2N/A gettext("LDAP ERROR (%d): %s."),
2N/A cookie->err_rc,
2N/A ldap_err2string(cookie->err_rc));
2N/A err = strdup(errstr);
2N/A if (cookie->err_from_result && cookie->err_rc ==
2N/A LDAP_SERVER_DOWN) {
2N/A MKERROR(LOG_INFO, *errorp,
2N/A cookie->err_rc, err, NULL);
2N/A } else {
2N/A MKERROR(LOG_WARNING, *errorp, cookie->err_rc,
2N/A err, NULL);
2N/A }
2N/A cookie->err_rc = NS_LDAP_INTERNAL;
2N/A cookie->errorp = *errorp;
2N/A return (ERROR);
2N/A default:
2N/A case ERROR:
2N/A (void) sprintf(errstr,
2N/A gettext("Internal State machine exit (%d).\n"),
2N/A cookie->state);
2N/A err = strdup(errstr);
2N/A MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2N/A NULL);
2N/A cookie->err_rc = NS_LDAP_INTERNAL;
2N/A cookie->errorp = *errorp;
2N/A return (ERROR);
2N/A }
2N/A
2N/A if (cookie->conn_user != NULL &&
2N/A cookie->conn_user->bad_mt_conn == B_TRUE) {
2N/A __s_api_conn_mt_close(cookie->conn_user, 0, NULL);
2N/A cookie->err_rc = cookie->conn_user->ns_rc;
2N/A cookie->errorp = cookie->conn_user->ns_error;
2N/A cookie->conn_user->ns_error = NULL;
2N/A return (ERROR);
2N/A }
2N/A
2N/A if (cycle == ONE_STEP) {
2N/A return (cookie->new_state);
2N/A }
2N/A cookie->state = cookie->new_state;
2N/A }
2N/A /*NOTREACHED*/
2N/A#if 0
2N/A (void) sprintf(errstr,
2N/A gettext("Unexpected State machine error.\n"));
2N/A err = strdup(errstr);
2N/A MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, NULL);
2N/A cookie->err_rc = NS_LDAP_INTERNAL;
2N/A cookie->errorp = *errorp;
2N/A return (ERROR);
2N/A#endif
2N/A}
2N/A
2N/A/*
2N/A * For a lookup of shadow data, if shadow update is enabled,
2N/A * check the calling process' privilege to ensure it's
2N/A * allowed to perform such operation.
2N/A */
2N/Astatic int
2N/Acheck_shadow(ns_ldap_cookie_t *cookie, const char *service)
2N/A{
2N/A char errstr[MAXERROR];
2N/A char *err;
2N/A boolean_t priv;
2N/A /* caller */
2N/A priv_set_t *ps;
2N/A /* zone */
2N/A priv_set_t *zs;
2N/A
2N/A /*
2N/A * If service is "shadow", we may need
2N/A * to use privilege credentials.
2N/A */
2N/A if ((strcmp(service, "shadow") == 0) &&
2N/A __ns_ldap_is_shadow_update_enabled()) {
2N/A /*
2N/A * Since we release admin credentials after
2N/A * connection is closed and we do not cache
2N/A * them, we allow any root or all zone
2N/A * privilege process to read shadow data.
2N/A */
2N/A priv = (geteuid() == 0);
2N/A if (!priv) {
2N/A /* caller */
2N/A ps = priv_allocset();
2N/A
2N/A (void) getppriv(PRIV_EFFECTIVE, ps);
2N/A zs = priv_str_to_set("zone", ",", NULL);
2N/A priv = priv_isequalset(ps, zs);
2N/A priv_freeset(ps);
2N/A priv_freeset(zs);
2N/A }
2N/A if (!priv) {
2N/A (void) sprintf(errstr,
2N/A gettext("Permission denied"));
2N/A err = strdup(errstr);
2N/A if (err == NULL)
2N/A return (NS_LDAP_MEMORY);
2N/A MKERROR(LOG_INFO, cookie->errorp, NS_LDAP_INTERNAL, err,
2N/A NULL);
2N/A return (NS_LDAP_INTERNAL);
2N/A }
2N/A cookie->i_flags |= NS_LDAP_READ_SHADOW;
2N/A /*
2N/A * We do not want to reuse connection (hence
2N/A * keep it open) with admin credentials.
2N/A * If NS_LDAP_KEEP_CONN is set, reject the
2N/A * request.
2N/A */
2N/A if (cookie->i_flags & NS_LDAP_KEEP_CONN)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A cookie->i_flags |= NS_LDAP_NEW_CONN;
2N/A }
2N/A
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * internal function for __ns_ldap_list
2N/A */
2N/Astatic int
2N/Aldap_list(
2N/A ns_ldap_list_batch_t *batch,
2N/A const char *service,
2N/A const char *filter,
2N/A const char *sortattr,
2N/A int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2N/A char **realfilter, const void *userdata),
2N/A const char * const *attribute,
2N/A const ns_cred_t *auth,
2N/A const int flags,
2N/A ns_ldap_result_t **rResult, /* return result entries */
2N/A ns_ldap_error_t **errorp,
2N/A int *rcp,
2N/A int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
2N/A const void *userdata, ns_conn_user_t *conn_user,
2N/A const char * const *extra_info_attr,
2N/A ns_ldap_entry_t **extra_info)
2N/A{
2N/A ns_ldap_cookie_t *cookie;
2N/A ns_ldap_search_desc_t **sdlist = NULL;
2N/A ns_ldap_search_desc_t *dptr;
2N/A ns_ldap_error_t *error = NULL;
2N/A char **dns = NULL;
2N/A int scope;
2N/A int rc;
2N/A int from_result;
2N/A
2N/A *errorp = NULL;
2N/A *rResult = NULL;
2N/A if (extra_info != NULL)
2N/A *extra_info = NULL;
2N/A *rcp = NS_LDAP_SUCCESS;
2N/A
2N/A /*
2N/A * Sanity check - NS_LDAP_READ_SHADOW is for our
2N/A * own internal use.
2N/A */
2N/A if (flags & NS_LDAP_READ_SHADOW)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A /* Initialize State machine cookie */
2N/A cookie = init_search_state_machine();
2N/A if (cookie == NULL) {
2N/A *rcp = NS_LDAP_MEMORY;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A cookie->conn_user = conn_user;
2N/A
2N/A /* see if need to follow referrals */
2N/A rc = __s_api_toFollowReferrals(flags,
2N/A &cookie->followRef, errorp);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A delete_search_cookie(cookie);
2N/A *rcp = rc;
2N/A return (rc);
2N/A }
2N/A
2N/A /* get the service descriptor - or create a default one */
2N/A rc = __s_api_get_SSD_from_SSDtoUse_service(service,
2N/A &sdlist, &error);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A delete_search_cookie(cookie);
2N/A *errorp = error;
2N/A *rcp = rc;
2N/A return (rc);
2N/A }
2N/A
2N/A if (sdlist == NULL) {
2N/A /* Create default service Desc */
2N/A sdlist = (ns_ldap_search_desc_t **)calloc(2,
2N/A sizeof (ns_ldap_search_desc_t *));
2N/A if (sdlist == NULL) {
2N/A delete_search_cookie(cookie);
2N/A cookie = NULL;
2N/A *rcp = NS_LDAP_MEMORY;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A dptr = (ns_ldap_search_desc_t *)
2N/A calloc(1, sizeof (ns_ldap_search_desc_t));
2N/A if (dptr == NULL) {
2N/A free(sdlist);
2N/A delete_search_cookie(cookie);
2N/A cookie = NULL;
2N/A *rcp = NS_LDAP_MEMORY;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A sdlist[0] = dptr;
2N/A
2N/A /* default base */
2N/A rc = __s_api_getDNs(&dns, service, &cookie->errorp);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A if (dns) {
2N/A __s_api_free2dArray(dns);
2N/A dns = NULL;
2N/A }
2N/A *errorp = cookie->errorp;
2N/A cookie->errorp = NULL;
2N/A delete_search_cookie(cookie);
2N/A cookie = NULL;
2N/A *rcp = rc;
2N/A return (rc);
2N/A }
2N/A dptr->basedn = strdup(dns[0]);
2N/A __s_api_free2dArray(dns);
2N/A dns = NULL;
2N/A
2N/A /* default scope */
2N/A scope = 0;
2N/A rc = __s_api_getSearchScope(&scope, &cookie->errorp);
2N/A dptr->scope = scope;
2N/A }
2N/A
2N/A cookie->sdlist = sdlist;
2N/A
2N/A /*
2N/A * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set
2N/A */
2N/A if (flags & NS_LDAP_PAGE_CTRL)
2N/A cookie->use_paging = TRUE;
2N/A else
2N/A cookie->use_paging = FALSE;
2N/A
2N/A /* Set up other arguments */
2N/A cookie->userdata = userdata;
2N/A if (init_filter_cb != NULL) {
2N/A cookie->init_filter_cb = init_filter_cb;
2N/A cookie->use_filtercb = 1;
2N/A }
2N/A if (callback != NULL) {
2N/A cookie->callback = callback;
2N/A cookie->use_usercb = 1;
2N/A }
2N/A
2N/A /* check_shadow() may add extra value to cookie->i_flags */
2N/A cookie->i_flags = flags;
2N/A if (service) {
2N/A cookie->service = strdup(service);
2N/A if (cookie->service == NULL) {
2N/A delete_search_cookie(cookie);
2N/A cookie = NULL;
2N/A *rcp = NS_LDAP_MEMORY;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A
2N/A /*
2N/A * If given, use the credential given by the caller, and
2N/A * skip the credential check required for shadow update.
2N/A */
2N/A if (auth == NULL) {
2N/A rc = check_shadow(cookie, service);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A *errorp = cookie->errorp;
2N/A cookie->errorp = NULL;
2N/A delete_search_cookie(cookie);
2N/A cookie = NULL;
2N/A *rcp = rc;
2N/A return (rc);
2N/A }
2N/A }
2N/A }
2N/A
2N/A cookie->i_filter = strdup(filter);
2N/A cookie->i_attr = attribute;
2N/A cookie->i_extra_info_attr = extra_info_attr;
2N/A cookie->i_auth = auth;
2N/A cookie->i_sortattr = sortattr;
2N/A
2N/A if (batch != NULL) {
2N/A cookie->batch = batch;
2N/A cookie->reinit_on_retriable_err = B_TRUE;
2N/A cookie->no_wait = B_TRUE;
2N/A (void) search_state_machine(cookie, INIT, 0);
2N/A cookie->no_wait = B_FALSE;
2N/A rc = cookie->err_rc;
2N/A
2N/A if (rc == NS_LDAP_SUCCESS) {
2N/A /*
2N/A * Here rc == NS_LDAP_SUCCESS means that the state
2N/A * machine init'ed successfully. The actual status
2N/A * of the search will be determined by
2N/A * __ns_ldap_list_batch_end(). Add the cookie to our
2N/A * batch.
2N/A */
2N/A cookie->caller_result = rResult;
2N/A cookie->caller_errorp = errorp;
2N/A cookie->caller_rc = rcp;
2N/A cookie->next_cookie_in_batch = batch->cookie_list;
2N/A batch->cookie_list = cookie;
2N/A batch->nactive++;
2N/A return (rc);
2N/A }
2N/A /*
2N/A * If state machine init failed then copy error to the caller
2N/A * and delete the cookie.
2N/A */
2N/A } else {
2N/A (void) search_state_machine(cookie, INIT, 0);
2N/A }
2N/A
2N/A /* Copy results back to user */
2N/A rc = cookie->err_rc;
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A if (cookie->extra_info != NULL) {
2N/A __ns_ldap_freeEntry(cookie->extra_info);
2N/A cookie->extra_info = NULL;
2N/A if (extra_info != NULL)
2N/A *extra_info = NULL;
2N/A }
2N/A if (conn_user != NULL && conn_user->ns_error != NULL) {
2N/A *errorp = conn_user->ns_error;
2N/A conn_user->ns_error = NULL;
2N/A } else
2N/A *errorp = cookie->errorp;
2N/A }
2N/A *rResult = cookie->result;
2N/A if (extra_info != NULL)
2N/A *extra_info = cookie->extra_info;
2N/A cookie->extra_info = NULL;
2N/A from_result = cookie->err_from_result;
2N/A
2N/A cookie->errorp = NULL;
2N/A cookie->result = NULL;
2N/A delete_search_cookie(cookie);
2N/A cookie = NULL;
2N/A
2N/A if (from_result == 0 && *rResult == NULL)
2N/A rc = NS_LDAP_NOTFOUND;
2N/A *rcp = rc;
2N/A return (rc);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * __ns_ldap_list performs one or more LDAP searches to a given
2N/A * directory server using service search descriptors and schema
2N/A * mapping as appropriate. The operation may be retried a
2N/A * couple of times in error situations.
2N/A */
2N/Aint
2N/A__ns_ldap_list(
2N/A const char *service,
2N/A const char *filter,
2N/A int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2N/A char **realfilter, const void *userdata),
2N/A const char * const *attribute,
2N/A const ns_cred_t *auth,
2N/A const int flags,
2N/A ns_ldap_result_t **rResult, /* return result entries */
2N/A ns_ldap_error_t **errorp,
2N/A int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
2N/A const void *userdata)
2N/A{
2N/A int mod_flags;
2N/A /*
2N/A * Strip the NS_LDAP_PAGE_CTRL option as this interface does not
2N/A * support this. If you want to use this option call the API
2N/A * __ns_ldap_list_sort() which has the sort attribute.
2N/A */
2N/A mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
2N/A
2N/A return (__ns_ldap_list_sort(service, filter, NULL, init_filter_cb,
2N/A attribute, auth, mod_flags, rResult, errorp,
2N/A callback, userdata));
2N/A}
2N/A
2N/A/*
2N/A * This function performs the same processing as __ns_ldap_list, but
2N/A * handles 'extra_info_attr' and returns 'extra_info'. This is to allow
2N/A * internal libsldap data, such as server type, to be requested/retured.
2N/A */
2N/Aint
2N/A__ns_ldap_list_ext(
2N/A const char *service,
2N/A const char *filter,
2N/A int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2N/A char **realfilter, const void *userdata),
2N/A const char * const *attribute,
2N/A const ns_cred_t *auth,
2N/A const int flags,
2N/A ns_ldap_result_t **rResult, /* return result entries */
2N/A ns_ldap_error_t **errorp,
2N/A int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
2N/A const void *userdata,
2N/A const char * const *extra_info_attr,
2N/A ns_ldap_entry_t **extra_info)
2N/A{
2N/A ns_conn_user_t *cu = NULL;
2N/A int try_cnt = 0;
2N/A int rc = NS_LDAP_SUCCESS, trc;
2N/A int mod_flags;
2N/A /*
2N/A * Strip the NS_LDAP_PAGE_CTRL option as this interface does not
2N/A * support this. If you want to use this option call the API
2N/A * __ns_ldap_list_sort() which has the sort attribute.
2N/A */
2N/A mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
2N/A
2N/A
2N/A for (;;) {
2N/A if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
2N/A &try_cnt, &rc, errorp) == 0)
2N/A break;
2N/A rc = ldap_list(NULL, service, filter, NULL, init_filter_cb,
2N/A attribute, auth, mod_flags, rResult, errorp, &trc, callback,
2N/A userdata, cu, extra_info_attr, extra_info);
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * __ns_ldap_list_sort performs one or more LDAP searches to a given
2N/A * directory server using service search descriptors and schema
2N/A * mapping as appropriate. The operation may be retried a
2N/A * couple of times in error situations.
2N/A */
2N/Aint
2N/A__ns_ldap_list_sort(
2N/A const char *service,
2N/A const char *filter,
2N/A const char *sortattr,
2N/A int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2N/A char **realfilter, const void *userdata),
2N/A const char * const *attribute,
2N/A const ns_cred_t *auth,
2N/A const int flags,
2N/A ns_ldap_result_t **rResult, /* return result entries */
2N/A ns_ldap_error_t **errorp,
2N/A int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
2N/A const void *userdata)
2N/A{
2N/A ns_conn_user_t *cu = NULL;
2N/A int try_cnt = 0;
2N/A int rc = NS_LDAP_SUCCESS, trc;
2N/A
2N/A for (;;) {
2N/A if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
2N/A &try_cnt, &rc, errorp) == 0)
2N/A break;
2N/A rc = ldap_list(NULL, service, filter, sortattr, init_filter_cb,
2N/A attribute, auth, flags, rResult, errorp, &trc, callback,
2N/A userdata, cu, NULL, NULL);
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * internal function for __ns_ldap_read_dn
2N/A */
2N/Astatic int
2N/Aldap_read_dn(
2N/A const char *dn,
2N/A const char *service,
2N/A int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2N/A char **realfilter, const void *userdata),
2N/A const char * const *attribute,
2N/A const ns_cred_t *auth,
2N/A const int flags,
2N/A ns_ldap_result_t **rResult, /* return result entries */
2N/A ns_ldap_error_t **errorp,
2N/A int *rcp,
2N/A int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
2N/A const void *userdata, ns_conn_user_t *conn_user,
2N/A const char * const *extra_info_attr,
2N/A ns_ldap_entry_t **extra_info)
2N/A{
2N/A ns_ldap_cookie_t *cookie = NULL;
2N/A ns_ldap_search_desc_t **sdlist = NULL;
2N/A ns_ldap_search_desc_t *dptr;
2N/A int rc;
2N/A int from_result;
2N/A
2N/A *errorp = NULL;
2N/A *rResult = NULL;
2N/A if (extra_info != NULL)
2N/A *extra_info = NULL;
2N/A rc = NS_LDAP_SUCCESS;
2N/A
2N/A /*
2N/A * Sanity check - NS_LDAP_READ_SHADOW is for our
2N/A * own internal use.
2N/A */
2N/A if (flags & NS_LDAP_READ_SHADOW) {
2N/A *rcp = NS_LDAP_INVALID_PARAM;
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A }
2N/A
2N/A /* Initialize State machine cookie */
2N/A cookie = init_search_state_machine();
2N/A if (cookie == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A cookie->conn_user = conn_user;
2N/A
2N/A /* see if need to follow referrals */
2N/A rc = __s_api_toFollowReferrals(flags,
2N/A &cookie->followRef, errorp);
2N/A if (rc != NS_LDAP_SUCCESS)
2N/A goto err_out;
2N/A
2N/A /* Create default service Desc */
2N/A sdlist = (ns_ldap_search_desc_t **)calloc(2,
2N/A sizeof (ns_ldap_search_desc_t *));
2N/A if (sdlist == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A dptr = (ns_ldap_search_desc_t *)
2N/A calloc(1, sizeof (ns_ldap_search_desc_t));
2N/A if (dptr == NULL) {
2N/A free(sdlist);
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A sdlist[0] = dptr;
2N/A cookie->sdlist = sdlist;
2N/A
2N/A /* search base is dn */
2N/A dptr->basedn = strdup(dn);
2N/A if (dptr->basedn == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A
2N/A /* search scope is base */
2N/A dptr->scope = NS_LDAP_SCOPE_BASE;
2N/A
2N/A cookie->use_paging = FALSE;
2N/A
2N/A /* Set up other arguments */
2N/A cookie->userdata = userdata;
2N/A if (init_filter_cb != NULL) {
2N/A cookie->init_filter_cb = init_filter_cb;
2N/A cookie->use_filtercb = 1;
2N/A }
2N/A if (callback != NULL) {
2N/A cookie->callback = callback;
2N/A cookie->use_usercb = 1;
2N/A }
2N/A
2N/A /* no need to perform attribute mapping on the DN */
2N/A cookie->i_flags |= NS_LDAP_NOT_CVT_DN;
2N/A cookie->i_filter = strdup("(objectClass=*)");
2N/A if (cookie->i_filter == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A cookie->i_attr = attribute;
2N/A cookie->i_extra_info_attr = extra_info_attr;
2N/A if (service != NULL) {
2N/A cookie->service = strdup(service);
2N/A if (cookie->service == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto err_out;
2N/A }
2N/A }
2N/A cookie->i_auth = auth;
2N/A
2N/A (void) search_state_machine(cookie, INIT, 0);
2N/A
2N/A /* Copy results back to user */
2N/A rc = cookie->err_rc;
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A if (cookie->extra_info != NULL) {
2N/A __ns_ldap_freeEntry(cookie->extra_info);
2N/A if (extra_info != NULL)
2N/A *extra_info = NULL;
2N/A }
2N/A if (conn_user != NULL && conn_user->ns_error != NULL) {
2N/A *errorp = conn_user->ns_error;
2N/A conn_user->ns_error = NULL;
2N/A } else
2N/A *errorp = cookie->errorp;
2N/A }
2N/A *rResult = cookie->result;
2N/A if (extra_info != NULL)
2N/A *extra_info = cookie->extra_info;
2N/A cookie->extra_info = NULL;
2N/A from_result = cookie->err_from_result;
2N/A
2N/A cookie->errorp = NULL;
2N/A cookie->result = NULL;
2N/A delete_search_cookie(cookie);
2N/A cookie = NULL;
2N/A
2N/A if (from_result == 0 && *rResult == NULL)
2N/A rc = NS_LDAP_NOTFOUND;
2N/A *rcp = rc;
2N/A return (rc);
2N/A
2N/Aerr_out:
2N/A if (cookie != NULL)
2N/A delete_search_cookie(cookie);
2N/A *rcp = rc;
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * __ns_ldap_read_dn reads a specific DN using LDAP search to a given
2N/A * directory server with service search descriptors and schema
2N/A * mapping as appropriate. The operation may be retried a
2N/A * couple of times in error situations.
2N/A */
2N/A
2N/Aint
2N/A__ns_ldap_read_dn(
2N/A const char *dn,
2N/A const char *service,
2N/A int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2N/A char **realfilter, const void *userdata),
2N/A const char * const *attribute,
2N/A const ns_cred_t *auth,
2N/A const int flags,
2N/A ns_ldap_result_t **rResult, /* return result entries */
2N/A ns_ldap_error_t **errorp,
2N/A int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
2N/A const void *userdata,
2N/A const char * const *extra_info_attr,
2N/A ns_ldap_entry_t **extra_info)
2N/A{
2N/A ns_conn_user_t *cu = NULL;
2N/A int try_cnt = 0;
2N/A int rc = NS_LDAP_SUCCESS, trc;
2N/A
2N/A for (;;) {
2N/A if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
2N/A &try_cnt, &rc, errorp) == 0)
2N/A break;
2N/A rc = ldap_read_dn(dn, service, init_filter_cb,
2N/A attribute, auth, flags, rResult, errorp, &trc,
2N/A callback, userdata, cu, extra_info_attr, extra_info);
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * Create and initialize batch for native LDAP lookups
2N/A */
2N/Aint
2N/A__ns_ldap_list_batch_start(ns_ldap_list_batch_t **batch)
2N/A{
2N/A *batch = calloc(1, sizeof (ns_ldap_list_batch_t));
2N/A if (*batch == NULL)
2N/A return (NS_LDAP_MEMORY);
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Add a LDAP search request to the batch.
2N/A */
2N/Aint
2N/A__ns_ldap_list_batch_add(
2N/A ns_ldap_list_batch_t *batch,
2N/A const char *service,
2N/A const char *filter,
2N/A int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2N/A char **realfilter, const void *userdata),
2N/A const char * const *attribute,
2N/A const ns_cred_t *auth,
2N/A const int flags,
2N/A ns_ldap_result_t **rResult, /* return result entries */
2N/A ns_ldap_error_t **errorp,
2N/A int *rcp,
2N/A int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
2N/A const void *userdata)
2N/A{
2N/A ns_conn_user_t *cu;
2N/A int rc;
2N/A int mod_flags;
2N/A
2N/A cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, 0);
2N/A if (cu == NULL) {
2N/A if (rcp != NULL)
2N/A *rcp = NS_LDAP_MEMORY;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A
2N/A /*
2N/A * Strip the NS_LDAP_PAGE_CTRL option as the batch interface does not
2N/A * support this.
2N/A */
2N/A mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
2N/A
2N/A rc = ldap_list(batch, service, filter, NULL, init_filter_cb, attribute,
2N/A auth, mod_flags, rResult, errorp, rcp, callback, userdata, cu,
2N/A NULL, NULL);
2N/A
2N/A /*
2N/A * Free the conn_user if the cookie was not batched. If the cookie
2N/A * was batched then __ns_ldap_list_batch_end or release will free the
2N/A * conn_user. The batch API instructs the search_state_machine
2N/A * to reinit and retry (max 3 times) on retriable LDAP errors.
2N/A */
2N/A if (rc != NS_LDAP_SUCCESS && cu != NULL) {
2N/A if (cu->conn_mt != NULL)
2N/A __s_api_conn_mt_return(cu);
2N/A __s_api_conn_user_free(cu);
2N/A }
2N/A return (rc);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Free batch.
2N/A */
2N/Avoid
2N/A__ns_ldap_list_batch_release(ns_ldap_list_batch_t *batch)
2N/A{
2N/A ns_ldap_cookie_t *c, *next;
2N/A
2N/A for (c = batch->cookie_list; c != NULL; c = next) {
2N/A next = c->next_cookie_in_batch;
2N/A if (c->conn_user != NULL) {
2N/A if (c->conn_user->conn_mt != NULL)
2N/A __s_api_conn_mt_return(c->conn_user);
2N/A __s_api_conn_user_free(c->conn_user);
2N/A c->conn_user = NULL;
2N/A }
2N/A delete_search_cookie(c);
2N/A }
2N/A free(batch);
2N/A}
2N/A
2N/A#define LD_USING_STATE(st) \
2N/A ((st == DO_SEARCH) || (st == MULTI_RESULT) || (st == NEXT_RESULT))
2N/A
2N/A/*
2N/A * Process batch. Everytime this function is called it selects an
2N/A * active cookie from the batch and single steps through the
2N/A * search_state_machine for the selected cookie. If lookup associated
2N/A * with the cookie is complete (success or error) then the cookie is
2N/A * removed from the batch and its memory freed.
2N/A *
2N/A * Returns 1 (if batch still has active cookies)
2N/A * 0 (if batch has no more active cookies)
2N/A * -1 (on errors, *rcp will contain the error code)
2N/A *
2N/A * The caller should call this function in a loop as long as it returns 1
2N/A * to process all the requests added to the batch. The results (and errors)
2N/A * will be available in the locations provided by the caller at the time of
2N/A * __ns_ldap_list_batch_add().
2N/A */
2N/Astatic
2N/Aint
2N/A__ns_ldap_list_batch_process(ns_ldap_list_batch_t *batch, int *rcp)
2N/A{
2N/A ns_ldap_cookie_t *c, *ptr, **prev;
2N/A ns_state_t state;
2N/A ns_ldap_error_t *errorp = NULL;
2N/A int rc;
2N/A
2N/A /* Check if are already done */
2N/A if (batch->nactive == 0)
2N/A return (0);
2N/A
2N/A /* Get the next cookie from the batch */
2N/A c = (batch->next_cookie == NULL) ?
2N/A batch->cookie_list : batch->next_cookie;
2N/A
2N/A batch->next_cookie = c->next_cookie_in_batch;
2N/A
2N/A /*
2N/A * Checks the status of the cookie's connection if it needs
2N/A * to use that connection for ldap_search_ext or ldap_result.
2N/A * If the connection is no longer good but worth retrying
2N/A * then reinit the search_state_machine for this cookie
2N/A * starting from the first search descriptor. REINIT will
2N/A * clear any leftover results if max retries have not been
2N/A * reached and redo the search (which may also involve
2N/A * following referrals again).
2N/A *
2N/A * Note that each cookie in the batch will make this
2N/A * determination when it reaches one of the LD_USING_STATES.
2N/A */
2N/A if (LD_USING_STATE(c->new_state) && c->conn_user != NULL) {
2N/A rc = __s_api_setup_getnext(c->conn_user, &c->err_rc, &errorp);
2N/A if (rc == LDAP_BUSY || rc == LDAP_UNAVAILABLE ||
2N/A rc == LDAP_UNWILLING_TO_PERFORM) {
2N/A if (errorp != NULL) {
2N/A (void) __ns_ldap_freeError(&c->errorp);
2N/A c->errorp = errorp;
2N/A }
2N/A c->new_state = REINIT;
2N/A } else if (rc == LDAP_CONNECT_ERROR ||
2N/A rc == LDAP_SERVER_DOWN) {
2N/A if (errorp != NULL) {
2N/A (void) __ns_ldap_freeError(&c->errorp);
2N/A c->errorp = errorp;
2N/A }
2N/A c->new_state = REINIT;
2N/A /*
2N/A * MT connection is not usable,
2N/A * close it before REINIT.
2N/A */
2N/A __s_api_conn_mt_close(
2N/A c->conn_user, rc, NULL);
2N/A } else if (rc != NS_LDAP_SUCCESS) {
2N/A if (rcp != NULL)
2N/A *rcp = rc;
2N/A *c->caller_result = NULL;
2N/A *c->caller_errorp = errorp;
2N/A *c->caller_rc = rc;
2N/A return (-1);
2N/A }
2N/A }
2N/A
2N/A for (;;) {
2N/A /* Single step through the search_state_machine */
2N/A state = search_state_machine(c, c->new_state, ONE_STEP);
2N/A switch (state) {
2N/A case LDAP_ERROR:
2N/A (void) search_state_machine(c, state, ONE_STEP);
2N/A (void) search_state_machine(c, CLEAR_RESULTS, ONE_STEP);
2N/A /* FALLTHROUGH */
2N/A case ERROR:
2N/A case EXIT:
2N/A *c->caller_result = c->result;
2N/A *c->caller_errorp = c->errorp;
2N/A *c->caller_rc =
2N/A (c->result == NULL && c->err_from_result == 0)
2N/A ? NS_LDAP_NOTFOUND : c->err_rc;
2N/A c->result = NULL;
2N/A c->errorp = NULL;
2N/A /* Remove the cookie from the batch */
2N/A ptr = batch->cookie_list;
2N/A prev = &batch->cookie_list;
2N/A while (ptr != NULL) {
2N/A if (ptr == c) {
2N/A *prev = ptr->next_cookie_in_batch;
2N/A break;
2N/A }
2N/A prev = &ptr->next_cookie_in_batch;
2N/A ptr = ptr->next_cookie_in_batch;
2N/A }
2N/A /* Delete cookie and decrement active cookie count */
2N/A if (c->conn_user != NULL) {
2N/A if (c->conn_user->conn_mt != NULL)
2N/A __s_api_conn_mt_return(c->conn_user);
2N/A __s_api_conn_user_free(c->conn_user);
2N/A c->conn_user = NULL;
2N/A }
2N/A delete_search_cookie(c);
2N/A batch->nactive--;
2N/A break;
2N/A case NEXT_RESULT:
2N/A case MULTI_RESULT:
2N/A /*
2N/A * This means that search_state_machine needs to do
2N/A * another ldap_result() for the cookie in question.
2N/A * We only do at most one ldap_result() per call in
2N/A * this function and therefore we return. This allows
2N/A * the caller to process results from other cookies
2N/A * in the batch without getting tied up on just one
2N/A * cookie.
2N/A */
2N/A break;
2N/A default:
2N/A /*
2N/A * This includes states that follow NEXT_RESULT or
2N/A * MULTI_RESULT such as PROCESS_RESULT and
2N/A * END_PROCESS_RESULT. We continue processing
2N/A * this cookie till we reach either the error, exit
2N/A * or the result states.
2N/A */
2N/A continue;
2N/A }
2N/A break;
2N/A }
2N/A
2N/A /* Return 0 if no more cookies left otherwise 1 */
2N/A return ((batch->nactive > 0) ? 1 : 0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Process all the active cookies in the batch and when none
2N/A * remains finalize the batch.
2N/A */
2N/Aint
2N/A__ns_ldap_list_batch_end(ns_ldap_list_batch_t *batch)
2N/A{
2N/A int rc = NS_LDAP_SUCCESS;
2N/A while (__ns_ldap_list_batch_process(batch, &rc) > 0)
2N/A ;
2N/A __ns_ldap_list_batch_release(batch);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * find_domainname performs one or more LDAP searches to
2N/A * find the value of the nisdomain attribute associated with
2N/A * the input DN (with no retry).
2N/A */
2N/A
2N/Astatic int
2N/Afind_domainname(const char *dn, char **domainname, const ns_cred_t *cred,
2N/A ns_ldap_error_t **errorp, ns_conn_user_t *conn_user)
2N/A{
2N/A
2N/A ns_ldap_cookie_t *cookie;
2N/A ns_ldap_search_desc_t **sdlist;
2N/A ns_ldap_search_desc_t *dptr;
2N/A int rc;
2N/A char **value;
2N/A int flags = 0;
2N/A
2N/A *domainname = NULL;
2N/A *errorp = NULL;
2N/A
2N/A /* Initialize State machine cookie */
2N/A cookie = init_search_state_machine();
2N/A if (cookie == NULL) {
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A cookie->conn_user = conn_user;
2N/A
2N/A /* see if need to follow referrals */
2N/A rc = __s_api_toFollowReferrals(flags,
2N/A &cookie->followRef, errorp);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A delete_search_cookie(cookie);
2N/A return (rc);
2N/A }
2N/A
2N/A /* Create default service Desc */
2N/A sdlist = (ns_ldap_search_desc_t **)calloc(2,
2N/A sizeof (ns_ldap_search_desc_t *));
2N/A if (sdlist == NULL) {
2N/A delete_search_cookie(cookie);
2N/A cookie = NULL;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A dptr = (ns_ldap_search_desc_t *)
2N/A calloc(1, sizeof (ns_ldap_search_desc_t));
2N/A if (dptr == NULL) {
2N/A free(sdlist);
2N/A delete_search_cookie(cookie);
2N/A cookie = NULL;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A sdlist[0] = dptr;
2N/A
2N/A /* search base is dn */
2N/A dptr->basedn = strdup(dn);
2N/A
2N/A /* search scope is base */
2N/A dptr->scope = NS_LDAP_SCOPE_BASE;
2N/A
2N/A /* search filter is "nisdomain=*" */
2N/A dptr->filter = strdup(_NIS_FILTER);
2N/A
2N/A cookie->sdlist = sdlist;
2N/A cookie->i_filter = strdup(dptr->filter);
2N/A cookie->i_attr = nis_domain_attrs;
2N/A cookie->i_auth = cred;
2N/A cookie->i_flags = 0;
2N/A
2N/A /* Process search */
2N/A rc = search_state_machine(cookie, INIT, 0);
2N/A
2N/A /* Copy domain name if found */
2N/A rc = cookie->err_rc;
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A if (conn_user != NULL && conn_user->ns_error != NULL) {
2N/A *errorp = conn_user->ns_error;
2N/A conn_user->ns_error = NULL;
2N/A } else
2N/A *errorp = cookie->errorp;
2N/A }
2N/A if (cookie->result == NULL)
2N/A rc = NS_LDAP_NOTFOUND;
2N/A if (rc == NS_LDAP_SUCCESS) {
2N/A value = __ns_ldap_getAttr(cookie->result->entry,
2N/A _NIS_DOMAIN);
2N/A if (value[0])
2N/A *domainname = strdup(value[0]);
2N/A else
2N/A rc = NS_LDAP_NOTFOUND;
2N/A }
2N/A if (cookie->result != NULL)
2N/A (void) __ns_ldap_freeResult(&cookie->result);
2N/A cookie->errorp = NULL;
2N/A delete_search_cookie(cookie);
2N/A cookie = NULL;
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * __s_api_find_domainname performs one or more LDAP searches to
2N/A * find the value of the nisdomain attribute associated with
2N/A * the input DN (with retry).
2N/A */
2N/A
2N/Astatic int
2N/A__s_api_find_domainname(const char *dn, char **domainname,
2N/A const ns_cred_t *cred, ns_ldap_error_t **errorp)
2N/A{
2N/A ns_conn_user_t *cu = NULL;
2N/A int try_cnt = 0;
2N/A int rc = NS_LDAP_SUCCESS;
2N/A
2N/A for (;;) {
2N/A if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
2N/A &try_cnt, &rc, errorp) == 0)
2N/A break;
2N/A rc = find_domainname(dn, domainname, cred, errorp, cu);
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/Astatic int
2N/AfirstEntry(
2N/A const char *service,
2N/A const char *filter,
2N/A const char *sortattr,
2N/A int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2N/A char **realfilter, const void *userdata),
2N/A const char * const *attribute,
2N/A const ns_cred_t *auth,
2N/A const int flags,
2N/A void **vcookie,
2N/A ns_ldap_result_t **result,
2N/A ns_ldap_error_t ** errorp,
2N/A const void *userdata,
2N/A ns_conn_user_t *conn_user,
2N/A const char * const *extra_info_attr,
2N/A ns_ldap_entry_t **extra_info)
2N/A{
2N/A ns_ldap_cookie_t *cookie = NULL;
2N/A ns_ldap_error_t *error = NULL;
2N/A ns_state_t state;
2N/A ns_ldap_search_desc_t **sdlist;
2N/A ns_ldap_search_desc_t *dptr;
2N/A char **dns = NULL;
2N/A int scope;
2N/A int rc;
2N/A
2N/A *errorp = NULL;
2N/A *result = NULL;
2N/A if (extra_info != NULL)
2N/A *extra_info = NULL;
2N/A
2N/A /*
2N/A * Sanity check - NS_LDAP_READ_SHADOW is for our
2N/A * own internal use.
2N/A */
2N/A if (flags & NS_LDAP_READ_SHADOW)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A /* get the service descriptor - or create a default one */
2N/A rc = __s_api_get_SSD_from_SSDtoUse_service(service,
2N/A &sdlist, &error);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A *errorp = error;
2N/A return (rc);
2N/A }
2N/A if (sdlist == NULL) {
2N/A /* Create default service Desc */
2N/A sdlist = (ns_ldap_search_desc_t **)calloc(2,
2N/A sizeof (ns_ldap_search_desc_t *));
2N/A if (sdlist == NULL) {
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A dptr = (ns_ldap_search_desc_t *)
2N/A calloc(1, sizeof (ns_ldap_search_desc_t));
2N/A if (dptr == NULL) {
2N/A free(sdlist);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A sdlist[0] = dptr;
2N/A
2N/A /* default base */
2N/A rc = __s_api_getDNs(&dns, service, &error);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A if (dns) {
2N/A __s_api_free2dArray(dns);
2N/A dns = NULL;
2N/A }
2N/A if (sdlist) {
2N/A (void) __ns_ldap_freeSearchDescriptors(
2N/A &sdlist);
2N/A
2N/A sdlist = NULL;
2N/A }
2N/A *errorp = error;
2N/A return (rc);
2N/A }
2N/A dptr->basedn = strdup(dns[0]);
2N/A __s_api_free2dArray(dns);
2N/A dns = NULL;
2N/A
2N/A /* default scope */
2N/A scope = 0;
2N/A cookie = init_search_state_machine();
2N/A if (cookie == NULL) {
2N/A if (sdlist) {
2N/A (void) __ns_ldap_freeSearchDescriptors(&sdlist);
2N/A sdlist = NULL;
2N/A }
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A rc = __s_api_getSearchScope(&scope, &cookie->errorp);
2N/A dptr->scope = scope;
2N/A }
2N/A
2N/A /* Initialize State machine cookie */
2N/A if (cookie == NULL)
2N/A cookie = init_search_state_machine();
2N/A if (cookie == NULL) {
2N/A if (sdlist) {
2N/A (void) __ns_ldap_freeSearchDescriptors(&sdlist);
2N/A sdlist = NULL;
2N/A }
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A
2N/A /* identify self as a getent user */
2N/A cookie->conn_user = conn_user;
2N/A
2N/A cookie->sdlist = sdlist;
2N/A
2N/A /* see if need to follow referrals */
2N/A rc = __s_api_toFollowReferrals(flags,
2N/A &cookie->followRef, errorp);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A delete_search_cookie(cookie);
2N/A return (rc);
2N/A }
2N/A
2N/A /*
2N/A * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set
2N/A */
2N/A if (flags & NS_LDAP_NO_PAGE_CTRL)
2N/A cookie->use_paging = FALSE;
2N/A else
2N/A cookie->use_paging = TRUE;
2N/A
2N/A /* Set up other arguments */
2N/A cookie->userdata = userdata;
2N/A if (init_filter_cb != NULL) {
2N/A cookie->init_filter_cb = init_filter_cb;
2N/A cookie->use_filtercb = 1;
2N/A }
2N/A cookie->use_usercb = 0;
2N/A /* check_shadow() may add extra value to cookie->i_flags */
2N/A cookie->i_flags = flags;
2N/A if (service) {
2N/A cookie->service = strdup(service);
2N/A if (cookie->service == NULL) {
2N/A delete_search_cookie(cookie);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A
2N/A /*
2N/A * If given, use the credential given by the caller, and
2N/A * skip the credential check required for shadow update.
2N/A */
2N/A if (auth == NULL) {
2N/A rc = check_shadow(cookie, service);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A *errorp = cookie->errorp;
2N/A cookie->errorp = NULL;
2N/A delete_search_cookie(cookie);
2N/A cookie = NULL;
2N/A return (rc);
2N/A }
2N/A }
2N/A }
2N/A
2N/A cookie->i_filter = strdup(filter);
2N/A cookie->i_attr = attribute;
2N/A cookie->i_extra_info_attr = extra_info_attr;
2N/A cookie->i_sortattr = sortattr;
2N/A cookie->i_auth = auth;
2N/A
2N/A state = INIT;
2N/A for (;;) {
2N/A state = search_state_machine(cookie, state, ONE_STEP);
2N/A switch (state) {
2N/A case PROCESS_RESULT:
2N/A *result = cookie->result;
2N/A cookie->result = NULL;
2N/A if (extra_info != NULL) {
2N/A *extra_info = cookie->extra_info;
2N/A cookie->extra_info = NULL;
2N/A }
2N/A *vcookie = (void *)cookie;
2N/A return (NS_LDAP_SUCCESS);
2N/A case LDAP_ERROR:
2N/A state = search_state_machine(cookie, state, ONE_STEP);
2N/A state = search_state_machine(cookie, CLEAR_RESULTS,
2N/A ONE_STEP);
2N/A /* FALLTHROUGH */
2N/A case ERROR:
2N/A rc = cookie->err_rc;
2N/A if (conn_user != NULL && conn_user->ns_error != NULL) {
2N/A *errorp = conn_user->ns_error;
2N/A conn_user->ns_error = NULL;
2N/A } else {
2N/A *errorp = cookie->errorp;
2N/A cookie->errorp = NULL;
2N/A }
2N/A delete_search_cookie(cookie);
2N/A return (rc);
2N/A case EXIT:
2N/A rc = cookie->err_rc;
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A *errorp = cookie->errorp;
2N/A cookie->errorp = NULL;
2N/A } else {
2N/A rc = NS_LDAP_NOTFOUND;
2N/A }
2N/A
2N/A delete_search_cookie(cookie);
2N/A return (rc);
2N/A
2N/A default:
2N/A break;
2N/A }
2N/A }
2N/A}
2N/A
2N/Aint
2N/A__ns_ldap_firstEntry(
2N/A const char *service,
2N/A const char *filter,
2N/A const char *vlv_sort,
2N/A int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2N/A char **realfilter, const void *userdata),
2N/A const char * const *attribute,
2N/A const ns_cred_t *auth,
2N/A const int flags,
2N/A void **vcookie,
2N/A ns_ldap_result_t **result,
2N/A ns_ldap_error_t ** errorp,
2N/A const void *userdata)
2N/A{
2N/A return (__ns_ldap_firstEntry_ext(service, filter, vlv_sort,
2N/A init_filter_cb, attribute, auth, flags, vcookie,
2N/A result, errorp, userdata, NULL, NULL));
2N/A}
2N/A
2N/A/*
2N/A * This function performs the same processing as __ns_ldap_firstEntry, but
2N/A * handles 'extra_info_attr' and returns 'extra_info'. This is to allow
2N/A * internal libsldap data, such as server type, to be requested/retured.
2N/A */
2N/Aint
2N/A__ns_ldap_firstEntry_ext(
2N/A const char *service,
2N/A const char *filter,
2N/A const char *vlv_sort,
2N/A int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2N/A char **realfilter, const void *userdata),
2N/A const char * const *attribute,
2N/A const ns_cred_t *auth,
2N/A const int flags,
2N/A void **vcookie,
2N/A ns_ldap_result_t **result,
2N/A ns_ldap_error_t ** errorp,
2N/A const void *userdata,
2N/A const char * const *extra_info_attr,
2N/A ns_ldap_entry_t **extra_info)
2N/A{
2N/A ns_conn_user_t *cu = NULL;
2N/A int try_cnt = 0;
2N/A int rc = NS_LDAP_SUCCESS;
2N/A
2N/A for (;;) {
2N/A if (__s_api_setup_retry_search(&cu, NS_CONN_USER_GETENT,
2N/A &try_cnt, &rc, errorp) == 0)
2N/A break;
2N/A rc = firstEntry(service, filter, vlv_sort, init_filter_cb,
2N/A attribute, auth, flags, vcookie, result, errorp, userdata,
2N/A cu, extra_info_attr, extra_info);
2N/A }
2N/A return (rc);
2N/A}
2N/A
2N/A/*ARGSUSED2*/
2N/Aint
2N/A__ns_ldap_nextEntry(void *vcookie, ns_ldap_result_t **result,
2N/A ns_ldap_error_t ** errorp)
2N/A{
2N/A ns_ldap_cookie_t *cookie;
2N/A ns_state_t state;
2N/A int rc;
2N/A
2N/A cookie = (ns_ldap_cookie_t *)vcookie;
2N/A cookie->result = NULL;
2N/A *result = NULL;
2N/A
2N/A if (cookie->conn_user != NULL) {
2N/A rc = __s_api_setup_getnext(cookie->conn_user,
2N/A &cookie->err_rc, errorp);
2N/A if (rc != NS_LDAP_SUCCESS)
2N/A return (rc);
2N/A }
2N/A
2N/A state = END_PROCESS_RESULT;
2N/A for (;;) {
2N/A state = search_state_machine(cookie, state, ONE_STEP);
2N/A switch (state) {
2N/A case PROCESS_RESULT:
2N/A *result = cookie->result;
2N/A cookie->result = NULL;
2N/A return (NS_LDAP_SUCCESS);
2N/A case LDAP_ERROR:
2N/A state = search_state_machine(cookie, state, ONE_STEP);
2N/A state = search_state_machine(cookie, CLEAR_RESULTS,
2N/A ONE_STEP);
2N/A /* FALLTHROUGH */
2N/A case ERROR:
2N/A rc = cookie->err_rc;
2N/A *errorp = cookie->errorp;
2N/A cookie->errorp = NULL;
2N/A return (rc);
2N/A case EXIT:
2N/A return (NS_LDAP_SUCCESS);
2N/A }
2N/A }
2N/A}
2N/A
2N/Aint
2N/A__ns_ldap_endEntry(
2N/A void **vcookie,
2N/A ns_ldap_error_t ** errorp)
2N/A{
2N/A ns_ldap_cookie_t *cookie;
2N/A int rc;
2N/A
2N/A if (*vcookie == NULL)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A cookie = (ns_ldap_cookie_t *)(*vcookie);
2N/A cookie->result = NULL;
2N/A
2N/A /* Complete search */
2N/A rc = search_state_machine(cookie, CLEAR_RESULTS, 0);
2N/A
2N/A /* Copy results back to user */
2N/A rc = cookie->err_rc;
2N/A if (rc != NS_LDAP_SUCCESS)
2N/A *errorp = cookie->errorp;
2N/A
2N/A cookie->errorp = NULL;
2N/A if (cookie->conn_user != NULL) {
2N/A if (cookie->conn_user->conn_mt != NULL)
2N/A __s_api_conn_mt_return(cookie->conn_user);
2N/A __s_api_conn_user_free(cookie->conn_user);
2N/A }
2N/A delete_search_cookie(cookie);
2N/A cookie = NULL;
2N/A *vcookie = NULL;
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A
2N/Aint
2N/A__ns_ldap_freeResult(ns_ldap_result_t **result)
2N/A{
2N/A
2N/A ns_ldap_entry_t *curEntry = NULL;
2N/A ns_ldap_entry_t *delEntry = NULL;
2N/A int i;
2N/A ns_ldap_result_t *res = *result;
2N/A
2N/A#ifdef DEBUG
2N/A (void) fprintf(stderr, "__ns_ldap_freeResult START\n");
2N/A#endif
2N/A if (res == NULL)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A if (res->entry != NULL)
2N/A curEntry = res->entry;
2N/A
2N/A for (i = 0; i < res->entries_count; i++) {
2N/A if (curEntry != NULL) {
2N/A delEntry = curEntry;
2N/A curEntry = curEntry->next;
2N/A __ns_ldap_freeEntry(delEntry);
2N/A }
2N/A }
2N/A
2N/A free(res);
2N/A *result = NULL;
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/A__ns_ldap_auth(const ns_cred_t *auth,
2N/A const int flags,
2N/A ns_ldap_error_t **errorp,
2N/A LDAPControl **serverctrls,
2N/A LDAPControl **clientctrls)
2N/A{
2N/A
2N/A ConnectionID connectionId = -1;
2N/A Connection *conp;
2N/A int rc = 0;
2N/A int do_not_fail_if_new_pwd_reqd = 0;
2N/A int nopasswd_acct_mgmt = 0;
2N/A ns_conn_user_t *conn_user;
2N/A
2N/A
2N/A#ifdef DEBUG
2N/A (void) fprintf(stderr, "__ns_ldap_auth START\n");
2N/A#endif
2N/A
2N/A *errorp = NULL;
2N/A if (!auth)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A conn_user = __s_api_conn_user_init(NS_CONN_USER_AUTH,
2N/A NULL, B_FALSE);
2N/A
2N/A rc = __s_api_getConnection(NULL, flags | NS_LDAP_NEW_CONN,
2N/A auth, &connectionId, &conp, errorp,
2N/A do_not_fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
2N/A conn_user);
2N/A
2N/A if (conn_user != NULL)
2N/A __s_api_conn_user_free(conn_user);
2N/A
2N/A if (rc == NS_LDAP_OP_FAILED && *errorp)
2N/A (void) __ns_ldap_freeError(errorp);
2N/A
2N/A if (connectionId > -1)
2N/A DropConnection(connectionId, flags);
2N/A return (rc);
2N/A}
2N/A
2N/Achar **
2N/A__ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname)
2N/A{
2N/A int i;
2N/A
2N/A if (entry == NULL)
2N/A return (NULL);
2N/A for (i = 0; i < entry->attr_count; i++) {
2N/A if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == NULL)
2N/A return (entry->attr_pair[i]->attrvalue);
2N/A }
2N/A return (NULL);
2N/A}
2N/A
2N/Ans_ldap_attr_t *
2N/A__ns_ldap_getAttrStruct(const ns_ldap_entry_t *entry, const char *attrname)
2N/A{
2N/A int i;
2N/A
2N/A if (entry == NULL)
2N/A return (NULL);
2N/A for (i = 0; i < entry->attr_count; i++) {
2N/A if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == NULL)
2N/A return (entry->attr_pair[i]);
2N/A }
2N/A return (NULL);
2N/A}
2N/A
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/A__ns_ldap_uid2dn(const char *uid,
2N/A char **userDN,
2N/A const ns_cred_t *cred, /* cred is ignored */
2N/A ns_ldap_error_t **errorp)
2N/A{
2N/A ns_ldap_result_t *result = NULL;
2N/A char *filter, *userdata;
2N/A char errstr[MAXERROR];
2N/A char **value;
2N/A int rc = 0;
2N/A int i = 0;
2N/A size_t len;
2N/A
2N/A *errorp = NULL;
2N/A *userDN = NULL;
2N/A if ((uid == NULL) || (uid[0] == '\0'))
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A while (uid[i] != '\0') {
2N/A if (uid[i] == '=') {
2N/A *userDN = strdup(uid);
2N/A return (NS_LDAP_SUCCESS);
2N/A }
2N/A i++;
2N/A }
2N/A i = 0;
2N/A while ((uid[i] != '\0') && (isdigit(uid[i])))
2N/A i++;
2N/A if (uid[i] == '\0') {
2N/A len = strlen(UIDNUMFILTER) + strlen(uid) + 1;
2N/A filter = (char *)malloc(len);
2N/A if (filter == NULL) {
2N/A *userDN = NULL;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A (void) snprintf(filter, len, UIDNUMFILTER, uid);
2N/A
2N/A len = strlen(UIDNUMFILTER_SSD) + strlen(uid) + 1;
2N/A userdata = (char *)malloc(len);
2N/A if (userdata == NULL) {
2N/A *userDN = NULL;
2N/A free(filter);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A (void) snprintf(userdata, len, UIDNUMFILTER_SSD, uid);
2N/A } else {
2N/A len = strlen(UIDFILTER) + strlen(uid) + 1;
2N/A filter = (char *)malloc(len);
2N/A if (filter == NULL) {
2N/A *userDN = NULL;
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A (void) snprintf(filter, len, UIDFILTER, uid);
2N/A
2N/A len = strlen(UIDFILTER_SSD) + strlen(uid) + 1;
2N/A userdata = (char *)malloc(len);
2N/A if (userdata == NULL) {
2N/A *userDN = NULL;
2N/A free(filter);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A (void) snprintf(userdata, len, UIDFILTER_SSD, uid);
2N/A }
2N/A
2N/A /*
2N/A * we want to retrieve the DN as it appears in LDAP
2N/A * hence the use of NS_LDAP_NOT_CVT_DN in flags
2N/A */
2N/A rc = __ns_ldap_list("passwd", filter,
2N/A __s_api_merge_SSD_filter,
2N/A NULL, cred, NS_LDAP_NOT_CVT_DN,
2N/A &result, errorp, NULL,
2N/A userdata);
2N/A free(filter);
2N/A filter = NULL;
2N/A free(userdata);
2N/A userdata = NULL;
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A if (result) {
2N/A (void) __ns_ldap_freeResult(&result);
2N/A result = NULL;
2N/A }
2N/A return (rc);
2N/A }
2N/A if (result->entries_count > 1) {
2N/A (void) __ns_ldap_freeResult(&result);
2N/A result = NULL;
2N/A *userDN = NULL;
2N/A (void) sprintf(errstr,
2N/A gettext("Too many entries are returned for %s"), uid);
2N/A MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
2N/A NULL);
2N/A return (NS_LDAP_INTERNAL);
2N/A }
2N/A
2N/A value = __ns_ldap_getAttr(result->entry, "dn");
2N/A *userDN = strdup(value[0]);
2N/A (void) __ns_ldap_freeResult(&result);
2N/A result = NULL;
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/A__ns_ldap_host2dn(const char *host,
2N/A const char *domain,
2N/A char **hostDN,
2N/A const ns_cred_t *cred, /* cred is ignored */
2N/A ns_ldap_error_t **errorp)
2N/A{
2N/A ns_ldap_result_t *result = NULL;
2N/A char *filter, *userdata;
2N/A char errstr[MAXERROR];
2N/A char **value;
2N/A int rc;
2N/A size_t len;
2N/A
2N/A/*
2N/A * XXX
2N/A * the domain parameter needs to be used in case domain is not local, if
2N/A * this routine is to support multi domain setups, it needs lots of work...
2N/A */
2N/A *errorp = NULL;
2N/A *hostDN = NULL;
2N/A if ((host == NULL) || (host[0] == '\0'))
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A len = strlen(HOSTFILTER) + strlen(host) + 1;
2N/A filter = (char *)malloc(len);
2N/A if (filter == NULL) {
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A (void) snprintf(filter, len, HOSTFILTER, host);
2N/A
2N/A len = strlen(HOSTFILTER_SSD) + strlen(host) + 1;
2N/A userdata = (char *)malloc(len);
2N/A if (userdata == NULL) {
2N/A free(filter);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A (void) snprintf(userdata, len, HOSTFILTER_SSD, host);
2N/A
2N/A /*
2N/A * we want to retrieve the DN as it appears in LDAP
2N/A * hence the use of NS_LDAP_NOT_CVT_DN in flags
2N/A */
2N/A rc = __ns_ldap_list("hosts", filter,
2N/A __s_api_merge_SSD_filter,
2N/A NULL, cred, NS_LDAP_NOT_CVT_DN, &result,
2N/A errorp, NULL,
2N/A userdata);
2N/A free(filter);
2N/A filter = NULL;
2N/A free(userdata);
2N/A userdata = NULL;
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A if (result) {
2N/A (void) __ns_ldap_freeResult(&result);
2N/A result = NULL;
2N/A }
2N/A return (rc);
2N/A }
2N/A
2N/A if (result->entries_count > 1) {
2N/A (void) __ns_ldap_freeResult(&result);
2N/A result = NULL;
2N/A *hostDN = NULL;
2N/A (void) sprintf(errstr,
2N/A gettext("Too many entries are returned for %s"), host);
2N/A MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
2N/A NULL);
2N/A return (NS_LDAP_INTERNAL);
2N/A }
2N/A
2N/A value = __ns_ldap_getAttr(result->entry, "dn");
2N/A *hostDN = strdup(value[0]);
2N/A (void) __ns_ldap_freeResult(&result);
2N/A result = NULL;
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/A__ns_ldap_dn2domain(const char *dn,
2N/A char **domain,
2N/A const ns_cred_t *cred,
2N/A ns_ldap_error_t **errorp)
2N/A{
2N/A int rc, pnum, i, j, len = 0;
2N/A char *newdn, **rdns = NULL;
2N/A char **dns, *dn1;
2N/A
2N/A *errorp = NULL;
2N/A
2N/A if (domain == NULL)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A else
2N/A *domain = NULL;
2N/A
2N/A if ((dn == NULL) || (dn[0] == '\0'))
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A /*
2N/A * break dn into rdns
2N/A */
2N/A dn1 = strdup(dn);
2N/A if (dn1 == NULL)
2N/A return (NS_LDAP_MEMORY);
2N/A rdns = ldap_explode_dn(dn1, 0);
2N/A free(dn1);
2N/A if (rdns == NULL || *rdns == NULL)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A for (i = 0; rdns[i]; i++)
2N/A len += strlen(rdns[i]) + 1;
2N/A pnum = i;
2N/A
2N/A newdn = (char *)malloc(len + 1);
2N/A dns = (char **)calloc(pnum, sizeof (char *));
2N/A if (newdn == NULL || dns == NULL) {
2N/A if (newdn)
2N/A free(newdn);
2N/A ldap_value_free(rdns);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A
2N/A /* construct a semi-normalized dn, newdn */
2N/A *newdn = '\0';
2N/A for (i = 0; rdns[i]; i++) {
2N/A dns[i] = newdn + strlen(newdn);
2N/A (void) strcat(newdn,
2N/A __s_api_remove_rdn_space(rdns[i]));
2N/A (void) strcat(newdn, ",");
2N/A }
2N/A /* remove the last ',' */
2N/A newdn[strlen(newdn) - 1] = '\0';
2N/A ldap_value_free(rdns);
2N/A
2N/A /*
2N/A * loop and find the domain name associated with newdn,
2N/A * removing rdn one by one from left to right
2N/A */
2N/A for (i = 0; i < pnum; i++) {
2N/A
2N/A if (*errorp)
2N/A (void) __ns_ldap_freeError(errorp);
2N/A
2N/A /*
2N/A * try cache manager first
2N/A */
2N/A rc = __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN,
2N/A dns[i], domain);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A /*
2N/A * try ldap server second
2N/A */
2N/A rc = __s_api_find_domainname(dns[i], domain,
2N/A cred, errorp);
2N/A } else {
2N/A /*
2N/A * skip the last one,
2N/A * since it is already cached by ldap_cachemgr
2N/A */
2N/A i--;
2N/A }
2N/A if (rc == NS_LDAP_SUCCESS) {
2N/A if (__s_api_nscd_proc()) {
2N/A /*
2N/A * If it's nscd, ask cache manager to save the
2N/A * dn to domain mapping(s)
2N/A */
2N/A for (j = 0; j <= i; j++) {
2N/A (void) __s_api_set_cachemgr_data(
2N/A NS_CACHE_DN2DOMAIN,
2N/A dns[j],
2N/A *domain);
2N/A }
2N/A }
2N/A break;
2N/A }
2N/A }
2N/A
2N/A free(dns);
2N/A free(newdn);
2N/A if (rc != NS_LDAP_SUCCESS)
2N/A rc = NS_LDAP_NOTFOUND;
2N/A return (rc);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/A__ns_ldap_getServiceAuthMethods(const char *service,
2N/A ns_auth_t ***auth,
2N/A ns_ldap_error_t **errorp)
2N/A{
2N/A char errstr[MAXERROR];
2N/A int rc, i, done = 0;
2N/A int slen;
2N/A void **param;
2N/A char **sam, *srv, *send;
2N/A ns_auth_t **authpp = NULL, *ap;
2N/A int cnt, max;
2N/A ns_config_t *cfg;
2N/A ns_ldap_error_t *error = NULL;
2N/A
2N/A if (errorp == NULL)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A *errorp = NULL;
2N/A
2N/A if ((service == NULL) || (service[0] == '\0') ||
2N/A (auth == NULL))
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A *auth = NULL;
2N/A rc = __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P, &param, &error);
2N/A if (rc != NS_LDAP_SUCCESS || param == NULL) {
2N/A *errorp = error;
2N/A return (rc);
2N/A }
2N/A sam = (char **)param;
2N/A
2N/A cfg = __s_api_get_default_config();
2N/A cnt = 0;
2N/A
2N/A slen = strlen(service);
2N/A
2N/A for (; *sam; sam++) {
2N/A srv = *sam;
2N/A if (strncasecmp(service, srv, slen) != 0)
2N/A continue;
2N/A srv += slen;
2N/A if (*srv != COLONTOK)
2N/A continue;
2N/A send = srv;
2N/A srv++;
2N/A for (max = 1; (send = strchr(++send, SEMITOK)) != NULL;
2N/A max++) {}
2N/A authpp = (ns_auth_t **)calloc(++max, sizeof (ns_auth_t *));
2N/A if (authpp == NULL) {
2N/A (void) __ns_ldap_freeParam(&param);
2N/A __s_api_release_config(cfg);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A while (!done) {
2N/A send = strchr(srv, SEMITOK);
2N/A if (send != NULL) {
2N/A *send = '\0';
2N/A send++;
2N/A }
2N/A i = __s_get_enum_value(cfg, srv, NS_LDAP_AUTH_P);
2N/A if (i == -1) {
2N/A (void) __ns_ldap_freeParam(&param);
2N/A (void) sprintf(errstr,
2N/A gettext("Unsupported "
2N/A "serviceAuthenticationMethod: %s.\n"), srv);
2N/A MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
2N/A strdup(errstr), NULL);
2N/A __s_api_release_config(cfg);
2N/A (void) __ns_ldap_freeParam((void ***)&authpp);
2N/A return (NS_LDAP_CONFIG);
2N/A }
2N/A ap = __s_api_AuthEnumtoStruct((EnumAuthType_t)i);
2N/A if (ap == NULL) {
2N/A (void) __ns_ldap_freeParam(&param);
2N/A __s_api_release_config(cfg);
2N/A (void) __ns_ldap_freeParam((void ***)&authpp);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A authpp[cnt++] = ap;
2N/A if (send == NULL)
2N/A done = TRUE;
2N/A else
2N/A srv = send;
2N/A }
2N/A }
2N/A
2N/A *auth = authpp;
2N/A (void) __ns_ldap_freeParam(&param);
2N/A __s_api_release_config(cfg);
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This routine is called when certain scenario occurs
2N/A * e.g.
2N/A * service == auto_home
2N/A * SSD = automount: ou = mytest,
2N/A * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA
2N/A * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap
2N/A * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject
2N/A *
2N/A * The automountMapName is prepended implicitely but is mapped
2N/A * to AAA. So dn could appers as
2N/A * dn: AAA=auto_home,ou=bar,dc=foo,dc=com
2N/A * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com
2N/A * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com
2N/A * in the directory.
2N/A * This function is called to covert the mapped attr back to
2N/A * orig attr when the entries are searched and returned
2N/A */
2N/A
2N/Aint
2N/A__s_api_convert_automountmapname(const char *service, char **dn,
2N/A ns_ldap_error_t **errp)
2N/A{
2N/A
2N/A char **mapping = NULL;
2N/A char *mapped_attr = NULL;
2N/A char *automountmapname = "automountMapName";
2N/A char *buffer = NULL;
2N/A int rc = NS_LDAP_SUCCESS;
2N/A char errstr[MAXERROR];
2N/A
2N/A /*
2N/A * dn is an input/out parameter, check it first
2N/A */
2N/A
2N/A if (service == NULL || dn == NULL || *dn == NULL)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A /*
2N/A * Check to see if there is a mapped attribute for auto_xxx
2N/A */
2N/A
2N/A mapping = __ns_ldap_getMappedAttributes(service, automountmapname);
2N/A
2N/A /*
2N/A * if no mapped attribute for auto_xxx, try automount
2N/A */
2N/A
2N/A if (mapping == NULL)
2N/A mapping = __ns_ldap_getMappedAttributes(
2N/A "automount", automountmapname);
2N/A
2N/A /*
2N/A * if no mapped attribute is found, return SUCCESS (no op)
2N/A */
2N/A
2N/A if (mapping == NULL)
2N/A return (NS_LDAP_SUCCESS);
2N/A
2N/A /*
2N/A * if the mapped attribute is found and attr is not empty,
2N/A * copy it
2N/A */
2N/A
2N/A if (mapping[0] != NULL) {
2N/A mapped_attr = strdup(mapping[0]);
2N/A __s_api_free2dArray(mapping);
2N/A if (mapped_attr == NULL) {
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A } else {
2N/A __s_api_free2dArray(mapping);
2N/A
2N/A (void) snprintf(errstr, (2 * MAXERROR),
2N/A gettext("Attribute nisMapName is mapped to an "
2N/A "empty string.\n"));
2N/A
2N/A MKERROR(LOG_ERR, *errp, NS_CONFIG_SYNTAX,
2N/A strdup(errstr), NULL);
2N/A
2N/A return (NS_LDAP_CONFIG);
2N/A }
2N/A
2N/A /*
2N/A * Locate the mapped attribute in the dn
2N/A * and replace it if it exists
2N/A */
2N/A
2N/A rc = __s_api_replace_mapped_attr_in_dn(
2N/A (const char *) automountmapname, (const char *) mapped_attr,
2N/A (const char *) *dn, &buffer);
2N/A
2N/A /* clean up */
2N/A
2N/A free(mapped_attr);
2N/A
2N/A /*
2N/A * If mapped attr is found(buffer != NULL)
2N/A * a new dn is returned
2N/A * If no mapped attribute is in dn,
2N/A * return NS_LDAP_SUCCESS (no op)
2N/A * If no memory,
2N/A * return NS_LDAP_MEMORY (no op)
2N/A */
2N/A
2N/A if (buffer != NULL) {
2N/A free(*dn);
2N/A *dn = buffer;
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * If the mapped attr is found in the dn,
2N/A * return NS_LDAP_SUCCESS and a new_dn.
2N/A * If no mapped attr is found,
2N/A * return NS_LDAP_SUCCESS and *new_dn == NULL
2N/A * If there is not enough memory,
2N/A * return NS_LDAP_MEMORY and *new_dn == NULL
2N/A */
2N/A
2N/Aint
2N/A__s_api_replace_mapped_attr_in_dn(
2N/A const char *orig_attr, const char *mapped_attr,
2N/A const char *dn, char **new_dn)
2N/A{
2N/A
2N/A char **dnArray = NULL;
2N/A char *cur = NULL, *start = NULL;
2N/A int i = 0, found = 0;
2N/A int len = 0, orig_len = 0, mapped_len = 0;
2N/A int dn_len = 0, tmp_len = 0;
2N/A
2N/A *new_dn = NULL;
2N/A
2N/A /*
2N/A * separate dn into individual components
2N/A * e.g.
2N/A * "automountKey=user_01" , "automountMapName_test=auto_home", ...
2N/A */
2N/A dnArray = ldap_explode_dn(dn, 0);
2N/A
2N/A /*
2N/A * This will find "mapped attr=value" in dn.
2N/A * It won't find match if mapped attr appears
2N/A * in the value.
2N/A */
2N/A for (i = 0; dnArray[i] != NULL; i++) {
2N/A /*
2N/A * This function is called when reading from
2N/A * the directory so assume each component has "=".
2N/A * Any ill formatted dn should be rejected
2N/A * before adding to the directory
2N/A */
2N/A cur = strchr(dnArray[i], '=');
2N/A *cur = '\0';
2N/A if (strcasecmp(mapped_attr, dnArray[i]) == 0)
2N/A found = 1;
2N/A *cur = '=';
2N/A if (found) break;
2N/A }
2N/A
2N/A if (!found) {
2N/A __s_api_free2dArray(dnArray);
2N/A *new_dn = NULL;
2N/A return (NS_LDAP_SUCCESS);
2N/A }
2N/A /*
2N/A * The new length is *dn length + (difference between
2N/A * orig attr and mapped attr) + 1 ;
2N/A * e.g.
2N/A * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com
2N/A * ==>
2N/A * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
2N/A */
2N/A mapped_len = strlen(mapped_attr);
2N/A orig_len = strlen(orig_attr);
2N/A dn_len = strlen(dn);
2N/A len = dn_len + orig_len - mapped_len + 1;
2N/A *new_dn = (char *)calloc(1, len);
2N/A if (*new_dn == NULL) {
2N/A __s_api_free2dArray(dnArray);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A
2N/A /*
2N/A * Locate the mapped attr in the dn.
2N/A * Use dnArray[i] instead of mapped_attr
2N/A * because mapped_attr could appear in
2N/A * the value
2N/A */
2N/A
2N/A cur = strstr(dn, dnArray[i]);
2N/A __s_api_free2dArray(dnArray);
2N/A /* copy the portion before mapped attr in dn */
2N/A start = *new_dn;
2N/A tmp_len = cur - dn;
2N/A (void) memcpy((void *) start, (const void*) dn, tmp_len);
2N/A
2N/A /*
2N/A * Copy the orig_attr. e.g. automountMapName
2N/A * This replaces mapped attr with orig attr
2N/A */
2N/A start = start + (cur - dn); /* move cursor in buffer */
2N/A (void) memcpy((void *) start, (const void*) orig_attr, orig_len);
2N/A
2N/A /*
2N/A * Copy the portion after mapped attr in dn
2N/A */
2N/A cur = cur + mapped_len; /* move cursor in dn */
2N/A start = start + orig_len; /* move cursor in buffer */
2N/A (void) strcpy(start, cur);
2N/A
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Validate Filter functions
2N/A */
2N/A
2N/A/* ***** Start of modified libldap.so.5 filter parser ***** */
2N/A
2N/A/* filter parsing routine forward references */
2N/Astatic int adj_filter_list(char *str);
2N/Astatic int adj_simple_filter(char *str);
2N/Astatic int unescape_filterval(char *val);
2N/Astatic int hexchar2int(char c);
2N/Astatic int adj_substring_filter(char *val);
2N/A
2N/A
2N/A/*
2N/A * assumes string manipulation is in-line
2N/A * and all strings are sufficient in size
2N/A * return value is the position after 'c'
2N/A */
2N/A
2N/Astatic char *
2N/Aresync_str(char *str, char *next, char c)
2N/A{
2N/A char *ret;
2N/A
2N/A ret = str + strlen(str);
2N/A *next = c;
2N/A if (ret == next)
2N/A return (ret);
2N/A (void) strcat(str, next);
2N/A return (ret);
2N/A}
2N/A
2N/Astatic char *
2N/Afind_right_paren(char *s)
2N/A{
2N/A int balance, escape;
2N/A
2N/A balance = 1;
2N/A escape = 0;
2N/A while (*s && balance) {
2N/A if (escape == 0) {
2N/A if (*s == '(')
2N/A balance++;
2N/A else if (*s == ')')
2N/A balance--;
2N/A }
2N/A if (*s == '\\' && ! escape)
2N/A escape = 1;
2N/A else
2N/A escape = 0;
2N/A if (balance)
2N/A s++;
2N/A }
2N/A
2N/A return (*s ? s : NULL);
2N/A}
2N/A
2N/Astatic char *
2N/Aadj_complex_filter(char *str)
2N/A{
2N/A char *next;
2N/A
2N/A /*
2N/A * We have (x(filter)...) with str sitting on
2N/A * the x. We have to find the paren matching
2N/A * the one before the x and put the intervening
2N/A * filters by calling adj_filter_list().
2N/A */
2N/A
2N/A str++;
2N/A if ((next = find_right_paren(str)) == NULL)
2N/A return (NULL);
2N/A
2N/A *next = '\0';
2N/A if (adj_filter_list(str) == -1)
2N/A return (NULL);
2N/A next = resync_str(str, next, ')');
2N/A next++;
2N/A
2N/A return (next);
2N/A}
2N/A
2N/Astatic int
2N/Aadj_filter(char *str)
2N/A{
2N/A char *next;
2N/A int parens, balance, escape;
2N/A char *np, *cp, *dp;
2N/A
2N/A parens = 0;
2N/A while (*str) {
2N/A switch (*str) {
2N/A case '(':
2N/A str++;
2N/A parens++;
2N/A switch (*str) {
2N/A case '&':
2N/A if ((str = adj_complex_filter(str)) == NULL)
2N/A return (-1);
2N/A
2N/A parens--;
2N/A break;
2N/A
2N/A case '|':
2N/A if ((str = adj_complex_filter(str)) == NULL)
2N/A return (-1);
2N/A
2N/A parens--;
2N/A break;
2N/A
2N/A case '!':
2N/A if ((str = adj_complex_filter(str)) == NULL)
2N/A return (-1);
2N/A
2N/A parens--;
2N/A break;
2N/A
2N/A case '(':
2N/A /* illegal ((case - generated by conversion */
2N/A
2N/A /* find missing close) */
2N/A np = find_right_paren(str+1);
2N/A
2N/A /* error if not found */
2N/A if (np == NULL)
2N/A return (-1);
2N/A
2N/A /* remove redundant (and) */
2N/A for (dp = str, cp = str+1; cp < np; ) {
2N/A *dp++ = *cp++;
2N/A }
2N/A cp++;
2N/A while (*cp)
2N/A *dp++ = *cp++;
2N/A *dp = '\0';
2N/A
2N/A /* re-start test at original ( */
2N/A parens--;
2N/A str--;
2N/A break;
2N/A
2N/A default:
2N/A balance = 1;
2N/A escape = 0;
2N/A next = str;
2N/A while (*next && balance) {
2N/A if (escape == 0) {
2N/A if (*next == '(')
2N/A balance++;
2N/A else if (*next == ')')
2N/A balance--;
2N/A }
2N/A if (*next == '\\' && ! escape)
2N/A escape = 1;
2N/A else
2N/A escape = 0;
2N/A if (balance)
2N/A next++;
2N/A }
2N/A if (balance != 0)
2N/A return (-1);
2N/A
2N/A *next = '\0';
2N/A if (adj_simple_filter(str) == -1) {
2N/A return (-1);
2N/A }
2N/A next = resync_str(str, next, ')');
2N/A next++;
2N/A str = next;
2N/A parens--;
2N/A break;
2N/A }
2N/A break;
2N/A
2N/A case ')':
2N/A str++;
2N/A parens--;
2N/A break;
2N/A
2N/A case ' ':
2N/A str++;
2N/A break;
2N/A
2N/A default: /* assume it's a simple type=value filter */
2N/A next = strchr(str, '\0');
2N/A if (adj_simple_filter(str) == -1) {
2N/A return (-1);
2N/A }
2N/A str = next;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A return (parens ? -1 : 0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Put a list of filters like this "(filter1)(filter2)..."
2N/A */
2N/A
2N/Astatic int
2N/Aadj_filter_list(char *str)
2N/A{
2N/A char *next;
2N/A char save;
2N/A
2N/A while (*str) {
2N/A while (*str && isspace(*str))
2N/A str++;
2N/A if (*str == '\0')
2N/A break;
2N/A
2N/A if ((next = find_right_paren(str + 1)) == NULL)
2N/A return (-1);
2N/A save = *++next;
2N/A
2N/A /* now we have "(filter)" with str pointing to it */
2N/A *next = '\0';
2N/A if (adj_filter(str) == -1)
2N/A return (-1);
2N/A next = resync_str(str, next, save);
2N/A
2N/A str = next;
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
2N/A * of a filter expression, 0 otherwise. A valid string may contain only
2N/A * letters, numbers, hyphens, semicolons, colons and periods. examples:
2N/A * cn
2N/A * cn;lang-fr
2N/A * 1.2.3.4;binary;dynamic
2N/A * mail;dynamic
2N/A * cn:dn:1.2.3.4
2N/A *
2N/A * For compatibility with older servers, we also allow underscores in
2N/A * attribute types, even through they are not allowed by the LDAPv3 RFCs.
2N/A */
2N/Astatic int
2N/Ais_valid_attr(char *a)
2N/A{
2N/A for (; *a; a++) {
2N/A if (!isascii(*a)) {
2N/A return (0);
2N/A } else if (!isalnum(*a)) {
2N/A switch (*a) {
2N/A case '-':
2N/A case '.':
2N/A case ';':
2N/A case ':':
2N/A case '_':
2N/A break; /* valid */
2N/A default:
2N/A return (0);
2N/A }
2N/A }
2N/A }
2N/A return (1);
2N/A}
2N/A
2N/Astatic char *
2N/Afind_star(char *s)
2N/A{
2N/A for (; *s; ++s) {
2N/A switch (*s) {
2N/A case '*':
2N/A return (s);
2N/A case '\\':
2N/A ++s;
2N/A if (hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0)
2N/A ++s;
2N/A default:
2N/A break;
2N/A }
2N/A }
2N/A return (NULL);
2N/A}
2N/A
2N/Astatic int
2N/Aadj_simple_filter(char *str)
2N/A{
2N/A char *s, *s2, *s3, filterop;
2N/A char *value;
2N/A int ftype = 0;
2N/A int rc;
2N/A
2N/A rc = -1; /* pessimistic */
2N/A
2N/A if ((str = strdup(str)) == NULL) {
2N/A return (rc);
2N/A }
2N/A
2N/A if ((s = strchr(str, '=')) == NULL) {
2N/A goto free_and_return;
2N/A }
2N/A value = s + 1;
2N/A *s-- = '\0';
2N/A filterop = *s;
2N/A if (filterop == '<' || filterop == '>' || filterop == '~' ||
2N/A filterop == ':') {
2N/A *s = '\0';
2N/A }
2N/A
2N/A if (! is_valid_attr(str)) {
2N/A goto free_and_return;
2N/A }
2N/A
2N/A switch (filterop) {
2N/A case '<': /* LDAP_FILTER_LE */
2N/A case '>': /* LDAP_FILTER_GE */
2N/A case '~': /* LDAP_FILTER_APPROX */
2N/A break;
2N/A case ':': /* extended filter - v3 only */
2N/A /*
2N/A * extended filter looks like this:
2N/A *
2N/A * [type][':dn'][':'oid]':='value
2N/A *
2N/A * where one of type or :oid is required.
2N/A *
2N/A */
2N/A s2 = s3 = NULL;
2N/A if ((s2 = strrchr(str, ':')) == NULL) {
2N/A goto free_and_return;
2N/A }
2N/A if (strcasecmp(s2, ":dn") == 0) {
2N/A *s2 = '\0';
2N/A } else {
2N/A *s2 = '\0';
2N/A if ((s3 = strrchr(str, ':')) != NULL) {
2N/A if (strcasecmp(s3, ":dn") != 0) {
2N/A goto free_and_return;
2N/A }
2N/A *s3 = '\0';
2N/A }
2N/A }
2N/A if (unescape_filterval(value) < 0) {
2N/A goto free_and_return;
2N/A }
2N/A rc = 0;
2N/A goto free_and_return;
2N/A /* break; */
2N/A default:
2N/A if (find_star(value) == NULL) {
2N/A ftype = 0; /* LDAP_FILTER_EQUALITY */
2N/A } else if (strcmp(value, "*") == 0) {
2N/A ftype = 1; /* LDAP_FILTER_PRESENT */
2N/A } else {
2N/A rc = adj_substring_filter(value);
2N/A goto free_and_return;
2N/A }
2N/A break;
2N/A }
2N/A
2N/A if (ftype != 0) { /* == LDAP_FILTER_PRESENT */
2N/A rc = 0;
2N/A } else if (unescape_filterval(value) >= 0) {
2N/A rc = 0;
2N/A }
2N/A if (rc != -1) {
2N/A rc = 0;
2N/A }
2N/A
2N/Afree_and_return:
2N/A free(str);
2N/A return (rc);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
2N/A * sequences within the null-terminated string 'val'.
2N/A *
2N/A * If 'val' contains invalid escape sequences we return -1.
2N/A * Otherwise return 1
2N/A */
2N/Astatic int
2N/Aunescape_filterval(char *val)
2N/A{
2N/A int escape, firstdigit;
2N/A char *s;
2N/A
2N/A firstdigit = 0;
2N/A escape = 0;
2N/A for (s = val; *s; s++) {
2N/A if (escape) {
2N/A /*
2N/A * first try LDAPv3 escape (hexadecimal) sequence
2N/A */
2N/A if (hexchar2int(*s) < 0) {
2N/A if (firstdigit) {
2N/A /*
2N/A * LDAPv2 (RFC1960) escape sequence
2N/A */
2N/A escape = 0;
2N/A } else {
2N/A return (-1);
2N/A }
2N/A }
2N/A if (firstdigit) {
2N/A firstdigit = 0;
2N/A } else {
2N/A escape = 0;
2N/A }
2N/A
2N/A } else if (*s != '\\') {
2N/A escape = 0;
2N/A
2N/A } else {
2N/A escape = 1;
2N/A firstdigit = 1;
2N/A }
2N/A }
2N/A
2N/A return (1);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * convert character 'c' that represents a hexadecimal digit to an integer.
2N/A * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
2N/A * otherwise the converted value is returned.
2N/A */
2N/Astatic int
2N/Ahexchar2int(char c)
2N/A{
2N/A if (c >= '0' && c <= '9') {
2N/A return (c - '0');
2N/A }
2N/A if (c >= 'A' && c <= 'F') {
2N/A return (c - 'A' + 10);
2N/A }
2N/A if (c >= 'a' && c <= 'f') {
2N/A return (c - 'a' + 10);
2N/A }
2N/A return (-1);
2N/A}
2N/A
2N/Astatic int
2N/Aadj_substring_filter(char *val)
2N/A{
2N/A char *nextstar;
2N/A
2N/A for (; val != NULL; val = nextstar) {
2N/A if ((nextstar = find_star(val)) != NULL) {
2N/A *nextstar++ = '\0';
2N/A }
2N/A
2N/A if (*val != '\0') {
2N/A if (unescape_filterval(val) < 0) {
2N/A return (-1);
2N/A }
2N/A }
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/* ***** End of modified libldap.so.5 filter parser ***** */
2N/A
2N/A
2N/A/*
2N/A * Walk filter, remove redundant parentheses in-line
2N/A * verify that the filter is reasonable
2N/A */
2N/Astatic int
2N/Avalidate_filter(ns_ldap_cookie_t *cookie)
2N/A{
2N/A char *filter = cookie->filter;
2N/A int rc;
2N/A
2N/A /* Parse filter looking for illegal values */
2N/A
2N/A rc = adj_filter(filter);
2N/A if (rc != 0) {
2N/A return (NS_LDAP_OP_FAILED);
2N/A }
2N/A
2N/A /* end of filter checking */
2N/A
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Set the account management request control that needs to be sent to server.
2N/A * This control is required to get the account management information of
2N/A * a user to do local account checking.
2N/A */
2N/Astatic int
2N/Asetup_acctmgmt_params(ns_ldap_cookie_t *cookie)
2N/A{
2N/A LDAPControl *req = NULL, **requestctrls;
2N/A
2N/A req = (LDAPControl *)malloc(sizeof (LDAPControl));
2N/A
2N/A if (req == NULL)
2N/A return (NS_LDAP_MEMORY);
2N/A
2N/A /* fill in the fields of this new control */
2N/A req->ldctl_iscritical = 1;
2N/A req->ldctl_oid = strdup(NS_LDAP_ACCOUNT_USABLE_CONTROL);
2N/A if (req->ldctl_oid == NULL) {
2N/A free(req);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A req->ldctl_value.bv_len = 0;
2N/A req->ldctl_value.bv_val = NULL;
2N/A
2N/A requestctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
2N/A if (requestctrls == NULL) {
2N/A ldap_control_free(req);
2N/A return (NS_LDAP_MEMORY);
2N/A }
2N/A
2N/A requestctrls[0] = req;
2N/A
2N/A cookie->p_serverctrls = requestctrls;
2N/A
2N/A return (NS_LDAP_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * int get_new_acct_more_info(BerElement *ber,
2N/A * AcctUsableResponse_t *acctResp)
2N/A *
2N/A * Decode the more_info data from an Account Management control response,
2N/A * when the account is not usable and when code style is from recent LDAP
2N/A * servers (see below comments for parse_acct_cont_resp_msg() to get more
2N/A * details on coding styles and ASN1 description).
2N/A *
2N/A * Expected BER encoding: {tbtbtbtiti}
2N/A * +t: tag is 0
2N/A * +b: TRUE if inactive due to account inactivation
2N/A * +t: tag is 1
2N/A * +b: TRUE if password has been reset
2N/A * +t: tag is 2
2N/A * +b: TRUE if password is expired
2N/A * +t: tag is 3
2N/A * +i: contains num of remaining grace, 0 means no grace
2N/A * +t: tag is 4
2N/A * +i: contains num of seconds before auto-unlock. -1 means acct is locked
2N/A * forever (i.e. until reset)
2N/A *
2N/A * Asumptions:
2N/A * - ber is not null
2N/A * - acctResp is not null and is initialized with default values for the
2N/A * fields in its AcctUsableResp.more_info structure
2N/A * - the ber stream is received in the correct order, per the ASN1 description.
2N/A * We do not check this order and make the asumption that it is correct.
2N/A * Note that the ber stream may not (and will not in most cases) contain
2N/A * all fields.
2N/A */
2N/Astatic int
2N/Aget_new_acct_more_info(BerElement *ber, AcctUsableResponse_t *acctResp)
2N/A{
2N/A int rc = NS_LDAP_SUCCESS;
2N/A char errstr[MAXERROR];
2N/A ber_tag_t rTag = LBER_DEFAULT;
2N/A ber_len_t rLen = 0;
2N/A ber_int_t rValue;
2N/A char *last;
2N/A int berRC = 0;
2N/A
2N/A /*
2N/A * Look at what more_info BER element is/are left to be decoded.
2N/A * look at each of them 1 by 1, without checking on their order
2N/A * and possible multi values.
2N/A */
2N/A for (rTag = ber_first_element(ber, &rLen, &last);
2N/A rTag != LBER_END_OF_SEQORSET;
2N/A rTag = ber_next_element(ber, &rLen, last)) {
2N/A
2N/A berRC = 0;
2N/A switch (rTag) {
2N/A case 0 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
2N/A /* inactive */
2N/A berRC = ber_scanf(ber, "b", &rValue);
2N/A if (berRC != LBER_ERROR) {
2N/A (acctResp->AcctUsableResp).more_info.
2N/A inactive = (rValue != 0) ? 1 : 0;
2N/A }
2N/A break;
2N/A
2N/A case 1 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
2N/A /* reset */
2N/A berRC = ber_scanf(ber, "b", &rValue);
2N/A if (berRC != LBER_ERROR) {
2N/A (acctResp->AcctUsableResp).more_info.reset
2N/A = (rValue != 0) ? 1 : 0;
2N/A }
2N/A break;
2N/A
2N/A case 2 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
2N/A /* expired */
2N/A berRC = ber_scanf(ber, "b", &rValue);
2N/A if (berRC != LBER_ERROR) {
2N/A (acctResp->AcctUsableResp).more_info.expired
2N/A = (rValue != 0) ? 1 : 0;
2N/A }
2N/A break;
2N/A
2N/A case 3 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
2N/A /* remaining grace */
2N/A berRC = ber_scanf(ber, "i", &rValue);
2N/A if (berRC != LBER_ERROR) {
2N/A (acctResp->AcctUsableResp).more_info.rem_grace
2N/A = rValue;
2N/A }
2N/A break;
2N/A
2N/A case 4 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
2N/A /* seconds before unlock */
2N/A berRC = ber_scanf(ber, "i", &rValue);
2N/A if (berRC != LBER_ERROR) {
2N/A (acctResp->AcctUsableResp).more_info.
2N/A sec_b4_unlock = rValue;
2N/A }
2N/A break;
2N/A
2N/A default :
2N/A (void) sprintf(errstr,
2N/A gettext("invalid reason tag 0x%x"), rTag);
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A rc = NS_LDAP_INTERNAL;
2N/A break;
2N/A }
2N/A if (berRC == LBER_ERROR) {
2N/A (void) sprintf(errstr,
2N/A gettext("error 0x%x decoding value for "
2N/A "tag 0x%x"), berRC, rTag);
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A rc = NS_LDAP_INTERNAL;
2N/A }
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A /* exit the for loop */
2N/A break;
2N/A }
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * int get_old_acct_opt_more_info(BerElement *ber,
2N/A * AcctUsableResponse_t *acctResp)
2N/A *
2N/A * Decode the optional more_info data from an Account Management control
2N/A * response, when the account is not usable and when code style is from LDAP
2N/A * server 5.2p4 (see below comments for parse_acct_cont_resp_msg() to get more
2N/A * details on coding styles and ASN1 description).
2N/A *
2N/A * Expected BER encoding: titi}
2N/A * +t: tag is 2
2N/A * +i: contains num of remaining grace, 0 means no grace
2N/A * +t: tag is 3
2N/A * +i: contains num of seconds before auto-unlock. -1 means acct is locked
2N/A * forever (i.e. until reset)
2N/A *
2N/A * Asumptions:
2N/A * - ber is a valid BER element
2N/A * - acctResp is initialized for the fields in its AcctUsableResp.more_info
2N/A * structure
2N/A */
2N/Astatic int
2N/Aget_old_acct_opt_more_info(ber_tag_t tag, BerElement *ber,
2N/A AcctUsableResponse_t *acctResp)
2N/A{
2N/A int rc = NS_LDAP_SUCCESS;
2N/A char errstr[MAXERROR];
2N/A ber_len_t len;
2N/A int rem_grace, sec_b4_unlock;
2N/A
2N/A switch (tag) {
2N/A case 2:
2N/A /* decode and maybe 3 is following */
2N/A if ((tag = ber_scanf(ber, "i", &rem_grace)) == LBER_ERROR) {
2N/A (void) sprintf(errstr, gettext("Can not get "
2N/A "rem_grace"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A rc = NS_LDAP_INTERNAL;
2N/A break;
2N/A }
2N/A (acctResp->AcctUsableResp).more_info.rem_grace = rem_grace;
2N/A
2N/A if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
2N/A /* this is a success case, break to exit */
2N/A (void) sprintf(errstr, gettext("No more "
2N/A "optional data"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A break;
2N/A }
2N/A
2N/A if (tag == 3) {
2N/A if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
2N/A (void) sprintf(errstr,
2N/A gettext("Can not get sec_b4_unlock "
2N/A "- 1st case"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A rc = NS_LDAP_INTERNAL;
2N/A break;
2N/A }
2N/A (acctResp->AcctUsableResp).more_info.sec_b4_unlock =
2N/A sec_b4_unlock;
2N/A } else { /* unknown tag */
2N/A (void) sprintf(errstr, gettext("Unknown tag "
2N/A "- 1st case"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A rc = NS_LDAP_INTERNAL;
2N/A break;
2N/A }
2N/A break;
2N/A
2N/A case 3:
2N/A if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
2N/A (void) sprintf(errstr, gettext("Can not get "
2N/A "sec_b4_unlock - 2nd case"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A rc = NS_LDAP_INTERNAL;
2N/A break;
2N/A }
2N/A (acctResp->AcctUsableResp).more_info.sec_b4_unlock =
2N/A sec_b4_unlock;
2N/A break;
2N/A
2N/A default: /* unknown tag */
2N/A (void) sprintf(errstr, gettext("Unknown tag - 2nd case"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A rc = NS_LDAP_INTERNAL;
2N/A break;
2N/A }
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * **** This function needs to be moved to libldap library ****
2N/A * parse_acct_cont_resp_msg() parses the message received by server according to
2N/A * following format (ASN1 notation):
2N/A *
2N/A * ACCOUNT_USABLE_RESPONSE::= CHOICE {
2N/A * is_available [0] INTEGER,
2N/A * ** seconds before expiration **
2N/A * is_not_available [1] more_info
2N/A * }
2N/A * more_info::= SEQUENCE {
2N/A * inactive [0] BOOLEAN DEFAULT FALSE,
2N/A * reset [1] BOOLEAN DEFAULT FALSE,
2N/A * expired [2] BOOLEAN DEFAULT FALSE,
2N/A * remaining_grace [3] INTEGER OPTIONAL,
2N/A * seconds_before_unlock [4] INTEGER OPTIONAL
2N/A * }
2N/A */
2N/A/*
2N/A * #define used to make the difference between coding style as done
2N/A * by LDAP server 5.2p4 and newer LDAP servers. There are 4 values:
2N/A * - DS52p4_USABLE: 5.2p4 coding style, account is usable
2N/A * - DS52p4_NOT_USABLE: 5.2p4 coding style, account is not usable
2N/A * - NEW_USABLE: newer LDAP servers coding style, account is usable
2N/A * - NEW_NOT_USABLE: newer LDAP servers coding style, account is not usable
2N/A *
2N/A * An account would be considered not usable if for instance:
2N/A * - it's been made inactive in the LDAP server
2N/A * - or its password was reset in the LDAP server database
2N/A * - or its password expired
2N/A * - or the account has been locked, possibly forever
2N/A */
2N/A#define DS52p4_USABLE 0x00
2N/A#define DS52p4_NOT_USABLE 0x01
2N/A#define NEW_USABLE 0x00 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE
2N/A#define NEW_NOT_USABLE 0x01 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED
2N/Astatic int
2N/Aparse_acct_cont_resp_msg(LDAPControl **ectrls, AcctUsableResponse_t *acctResp)
2N/A{
2N/A int rc = NS_LDAP_SUCCESS;
2N/A BerElement *ber;
2N/A ber_tag_t tag;
2N/A ber_len_t len;
2N/A int i;
2N/A char errstr[MAXERROR];
2N/A /* used for any coding style when account is usable */
2N/A int seconds_before_expiry;
2N/A /* used for 5.2p4 coding style when account is not usable */
2N/A int inactive, reset, expired;
2N/A
2N/A if (ectrls == NULL) {
2N/A (void) sprintf(errstr, gettext("Invalid ectrls parameter"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A }
2N/A
2N/A for (i = 0; ectrls[i] != NULL; i++) {
2N/A if (strcmp(ectrls[i]->ldctl_oid, NS_LDAP_ACCOUNT_USABLE_CONTROL)
2N/A == 0) {
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (ectrls[i] == NULL) {
2N/A /* Ldap control is not found */
2N/A (void) sprintf(errstr, gettext("Account Usable Control "
2N/A "not found"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A return (NS_LDAP_NOTFOUND);
2N/A }
2N/A
2N/A /* Allocate a BER element from the control value and parse it. */
2N/A if ((ber = ber_init(&ectrls[i]->ldctl_value)) == NULL)
2N/A return (NS_LDAP_MEMORY);
2N/A
2N/A if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
2N/A /* Ldap decoding error */
2N/A (void) sprintf(errstr, gettext("Error decoding 1st tag"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A ber_free(ber, 1);
2N/A return (NS_LDAP_INTERNAL);
2N/A }
2N/A
2N/A switch (tag) {
2N/A case DS52p4_USABLE:
2N/A case NEW_USABLE:
2N/A acctResp->choice = 0;
2N/A if (ber_scanf(ber, "i", &seconds_before_expiry)
2N/A == LBER_ERROR) {
2N/A /* Ldap decoding error */
2N/A (void) sprintf(errstr, gettext("Can not get "
2N/A "seconds_before_expiry"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A rc = NS_LDAP_INTERNAL;
2N/A break;
2N/A }
2N/A /* ber_scanf() succeeded */
2N/A (acctResp->AcctUsableResp).seconds_before_expiry =
2N/A seconds_before_expiry;
2N/A break;
2N/A
2N/A case DS52p4_NOT_USABLE:
2N/A acctResp->choice = 1;
2N/A if (ber_scanf(ber, "{bbb", &inactive, &reset, &expired)
2N/A == LBER_ERROR) {
2N/A /* Ldap decoding error */
2N/A (void) sprintf(errstr, gettext("Can not get "
2N/A "inactive/reset/expired"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A rc = NS_LDAP_INTERNAL;
2N/A break;
2N/A }
2N/A /* ber_scanf() succeeded */
2N/A (acctResp->AcctUsableResp).more_info.inactive =
2N/A ((inactive == 0) ? 0 : 1);
2N/A (acctResp->AcctUsableResp).more_info.reset =
2N/A ((reset == 0) ? 0 : 1);
2N/A (acctResp->AcctUsableResp).more_info.expired =
2N/A ((expired == 0) ? 0 : 1);
2N/A (acctResp->AcctUsableResp).more_info.rem_grace = 0;
2N/A (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
2N/A
2N/A if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
2N/A /* this is a success case, break to exit */
2N/A (void) sprintf(errstr, gettext("No optional data"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A break;
2N/A }
2N/A
2N/A /*
2N/A * Look at what optional more_info BER element is/are
2N/A * left to be decoded.
2N/A */
2N/A rc = get_old_acct_opt_more_info(tag, ber, acctResp);
2N/A break;
2N/A
2N/A case NEW_NOT_USABLE:
2N/A acctResp->choice = 1;
2N/A /*
2N/A * Recent LDAP servers won't code more_info data for default
2N/A * values (see above comments on ASN1 description for what
2N/A * fields have default values & what fields are optional).
2N/A */
2N/A (acctResp->AcctUsableResp).more_info.inactive = 0;
2N/A (acctResp->AcctUsableResp).more_info.reset = 0;
2N/A (acctResp->AcctUsableResp).more_info.expired = 0;
2N/A (acctResp->AcctUsableResp).more_info.rem_grace = 0;
2N/A (acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
2N/A
2N/A if (len == 0) {
2N/A /*
2N/A * Nothing else to decode; this is valid and we
2N/A * use default values set above.
2N/A */
2N/A (void) sprintf(errstr, gettext("more_info is "
2N/A "empty, using default values"));
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A break;
2N/A }
2N/A
2N/A /*
2N/A * Look at what more_info BER element is/are left to
2N/A * be decoded.
2N/A */
2N/A rc = get_new_acct_more_info(ber, acctResp);
2N/A break;
2N/A
2N/A default:
2N/A (void) sprintf(errstr, gettext("unknwon coding style "
2N/A "(tag: 0x%x)"), tag);
2N/A syslog(LOG_DEBUG, "libsldap: %s", errstr);
2N/A rc = NS_LDAP_INTERNAL;
2N/A break;
2N/A }
2N/A
2N/A ber_free(ber, 1);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * internal function for __ns_ldap_getAcctMgmt()
2N/A */
2N/Astatic int
2N/AgetAcctMgmt(const char *user, AcctUsableResponse_t *acctResp,
2N/A ns_conn_user_t *conn_user)
2N/A{
2N/A int scope, rc;
2N/A char ldapfilter[1024];
2N/A ns_ldap_cookie_t *cookie;
2N/A ns_ldap_search_desc_t **sdlist = NULL;
2N/A ns_ldap_search_desc_t *dptr;
2N/A ns_ldap_error_t *error = NULL;
2N/A char **dns = NULL;
2N/A char service[] = "shadow";
2N/A
2N/A if (user == NULL || acctResp == NULL)
2N/A return (NS_LDAP_INVALID_PARAM);
2N/A
2N/A /* Initialize State machine cookie */
2N/A cookie = init_search_state_machine();
2N/A if (cookie == NULL)
2N/A return (NS_LDAP_MEMORY);
2N/A cookie->conn_user = conn_user;
2N/A
2N/A /* see if need to follow referrals */
2N/A rc = __s_api_toFollowReferrals(0,
2N/A &cookie->followRef, &error);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A (void) __ns_ldap_freeError(&error);
2N/A goto out;
2N/A }
2N/A
2N/A /* get the service descriptor - or create a default one */
2N/A rc = __s_api_get_SSD_from_SSDtoUse_service(service,
2N/A &sdlist, &error);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A (void) __ns_ldap_freeError(&error);
2N/A goto out;
2N/A }
2N/A
2N/A if (sdlist == NULL) {
2N/A /* Create default service Desc */
2N/A sdlist = (ns_ldap_search_desc_t **)calloc(2,
2N/A sizeof (ns_ldap_search_desc_t *));
2N/A if (sdlist == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto out;
2N/A }
2N/A dptr = (ns_ldap_search_desc_t *)
2N/A calloc(1, sizeof (ns_ldap_search_desc_t));
2N/A if (dptr == NULL) {
2N/A free(sdlist);
2N/A rc = NS_LDAP_MEMORY;
2N/A goto out;
2N/A }
2N/A sdlist[0] = dptr;
2N/A
2N/A /* default base */
2N/A rc = __s_api_getDNs(&dns, service, &cookie->errorp);
2N/A if (rc != NS_LDAP_SUCCESS) {
2N/A if (dns) {
2N/A __s_api_free2dArray(dns);
2N/A dns = NULL;
2N/A }
2N/A (void) __ns_ldap_freeError(&(cookie->errorp));
2N/A cookie->errorp = NULL;
2N/A goto out;
2N/A }
2N/A dptr->basedn = strdup(dns[0]);
2N/A if (dptr->basedn == NULL) {
2N/A free(sdlist);
2N/A free(dptr);
2N/A if (dns) {
2N/A __s_api_free2dArray(dns);
2N/A dns = NULL;
2N/A }
2N/A rc = NS_LDAP_MEMORY;
2N/A goto out;
2N/A }
2N/A __s_api_free2dArray(dns);
2N/A dns = NULL;
2N/A
2N/A /* default scope */
2N/A scope = 0;
2N/A rc = __s_api_getSearchScope(&scope, &cookie->errorp);
2N/A dptr->scope = scope;
2N/A }
2N/A
2N/A cookie->sdlist = sdlist;
2N/A
2N/A cookie->service = strdup(service);
2N/A if (cookie->service == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto out;
2N/A }
2N/A
2N/A /* search for entries for this particular uid */
2N/A (void) snprintf(ldapfilter, sizeof (ldapfilter), "(uid=%s)", user);
2N/A cookie->i_filter = strdup(ldapfilter);
2N/A if (cookie->i_filter == NULL) {
2N/A rc = NS_LDAP_MEMORY;
2N/A goto out;
2N/A }
2N/A
2N/A /* create the control request */
2N/A if ((rc = setup_acctmgmt_params(cookie)) != NS_LDAP_SUCCESS)
2N/A goto out;
2N/A
2N/A /* Process search */
2N/A rc = search_state_machine(cookie, GET_ACCT_MGMT_INFO, 0);
2N/A
2N/A /* Copy results back to user */
2N/A rc = cookie->err_rc;
2N/A if (rc != NS_LDAP_SUCCESS)
2N/A (void) __ns_ldap_freeError(&(cookie->errorp));
2N/A
2N/A if (cookie->result == NULL)
2N/A goto out;
2N/A
2N/A if ((rc = parse_acct_cont_resp_msg(cookie->resultctrl, acctResp))
2N/A != NS_LDAP_SUCCESS)
2N/A goto out;
2N/A
2N/A rc = NS_LDAP_SUCCESS;
2N/A
2N/Aout:
2N/A delete_search_cookie(cookie);
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * __ns_ldap_getAcctMgmt() is called from pam account management stack
2N/A * for retrieving accounting information of users with no user password -
2N/A * eg. rlogin, rsh, etc. This function uses the account management control
2N/A * request to do a search on the server for the user in question. The
2N/A * response control returned from the server is got from the cookie.
2N/A * Input params: username of whose account mgmt information is to be got
2N/A * pointer to hold the parsed account management information
2N/A * Return values: NS_LDAP_SUCCESS on success or appropriate error
2N/A * code on failure
2N/A */
2N/Aint
2N/A__ns_ldap_getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp)
2N/A{
2N/A ns_conn_user_t *cu = NULL;
2N/A int try_cnt = 0;
2N/A int rc = NS_LDAP_SUCCESS;
2N/A ns_ldap_error_t *error = NULL;
2N/A
2N/A for (;;) {
2N/A if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
2N/A &try_cnt, &rc, &error) == 0)
2N/A break;
2N/A rc = getAcctMgmt(user, acctResp, cu);
2N/A }
2N/A return (rc);
2N/A}