1N/A/*
1N/A * CDDL HEADER START
1N/A *
1N/A * The contents of this file are subject to the terms of the
1N/A * Common Development and Distribution License (the "License").
1N/A * You may not use this file except in compliance with the License.
1N/A *
1N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1N/A * or http://www.opensolaris.org/os/licensing.
1N/A * See the License for the specific language governing permissions
1N/A * and limitations under the License.
1N/A *
1N/A * When distributing Covered Code, include this CDDL HEADER in each
1N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1N/A * If applicable, add the following below this CDDL HEADER, with the
1N/A * fields enclosed by brackets "[]" replaced with your own identifying
1N/A * information: Portions Copyright [yyyy] [name of copyright owner]
1N/A *
1N/A * CDDL HEADER END
1N/A */
1N/A
1N/A/*
1N/A * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
1N/A */
1N/A
1N/A#include <ctype.h>
1N/A#include <libintl.h>
1N/A#include <strings.h>
1N/A#include <stdio.h>
1N/A#include <tsol/label.h>
1N/A#include "../../../lib/libsldap/common/ns_sldap.h"
1N/A
1N/A
1N/A#define SAME 0
1N/A
1N/Astruct mapping {
1N/A char *database;
1N/A char *def_type;
1N/A char *objectclass;
1N/A char *actual_db;
1N/A};
1N/A
1N/A#define PUBLICKEY 0
1N/A
1N/Astatic struct mapping maplist[] = {
1N/A {"publickey", "uidnumber", "niskeyobject", "passwd"},
1N/A {"publickey", "cn", "niskeyobject", "host"},
1N/A {"bootparams", "cn", "bootableDevice", NULL},
1N/A {"ethers", "cn", "ieee802Device", NULL},
1N/A {"group", "cn", "posixgroup", NULL},
1N/A {"hosts", "cn", "iphost", NULL},
1N/A {"ipnodes", "cn", "iphost", NULL},
1N/A {"netgroup", "cn", "nisnetgroup", NULL},
1N/A {"netmasks", "ipnetworknumber", "ipnetwork", NULL},
1N/A {"networks", "ipnetworknumber", "ipnetwork", NULL},
1N/A {"passwd", "uid", "posixaccount", NULL},
1N/A {"protocols", "cn", "ipprotocol", NULL},
1N/A {"rpc", "cn", "oncrpc", NULL},
1N/A {"services", "cn", "ipservice", NULL},
1N/A {"aliases", "cn", "mailGroup", NULL},
1N/A {"project", "SolarisProjectID", "SolarisProject", NULL},
1N/A {"printers", "printer-uri", "sunPrinter", NULL},
1N/A {"shadow", "uid", "shadowaccount", NULL},
1N/A {"auth_attr", "cn", "SolarisAuthAttr", NULL},
1N/A {"prof_attr", "cn", "SolarisProfAttr", NULL},
1N/A {"exec_attr", "cn", "SolarisExecAttr", NULL},
1N/A {"user_attr", "uid", "SolarisUserAttr", NULL},
1N/A {"tnrhtp", "ipTnetTemplateName", "ipTnetTemplate", NULL},
1N/A {"tnrhdb", "ipTnetNumber", "ipTnetHost", NULL},
1N/A {NULL, NULL, NULL, NULL}
1N/A};
1N/A
1N/A#define PROF_ATTR_FILTER \
1N/A "(&(objectclass=SolarisProfAttr)(!(SolarisKernelSecurityPolicy=*))%s)"
1N/A#define TNRHTP_FILTER \
1N/A "(&(objectclass=ipTnetTemplate)(!(objectclass=ipTnetHost))%s)"
1N/A#define OC_FILTER "objectclass=%s"
1N/A#define OC_FLEN 15
1N/A#define OC_FILTER2 "(&(objectclass=%s)%s)"
1N/A#define OC_FLEN2 22
1N/A
1N/A/* Malloc and print error message in case of failure */
1N/A#define MALLOC(ptr, len) \
1N/A if ((ptr = (char *)malloc(len)) == NULL) { \
1N/A (void) fprintf(stderr, gettext("out of memory\n")); \
1N/A }
1N/A
1N/A/*
1N/A * Allocate memory for filter and user data. Set
1N/A * error to 1 if either of the mallocs fail.
1N/A * In addition, free the memory allocated for filter,
1N/A * if memory allocation for user data fails.
1N/A */
1N/A#define MALLOC_FILTER_UDATA(ptr1, len1, ptr2, len2, error) \
1N/A error = 0; \
1N/A MALLOC(ptr1, len1); \
1N/A if (!ptr1) { \
1N/A error = 1; \
1N/A } \
1N/A else { \
1N/A MALLOC(ptr2, len2); \
1N/A if (!ptr2) { \
1N/A error = 1; \
1N/A free(ptr1); \
1N/A } \
1N/A }
1N/A
1N/Avoid
1N/AprintMapping()
1N/A{
1N/A int i;
1N/A
1N/A (void) fprintf(stdout,
1N/A gettext("database default type objectclass\n"));
1N/A (void) fprintf(stdout,
1N/A gettext("============= ================= =============\n"));
1N/A /* first dump auto_* and automount which are not in maplist[] */
1N/A (void) fprintf(stdout, "%-15s%-20s%s\n", "auto_*", "automountKey",
1N/A "automount");
1N/A (void) fprintf(stdout, "%-15s%-20s%s\n", "automount",
1N/A "automountMapName", "automountMap");
1N/A for (i = 0; maplist[i].database != NULL; i++) {
1N/A /* skip printing shadow */
1N/A if (strcasecmp(maplist[i].database, "shadow") == 0)
1N/A continue;
1N/A if (!is_system_labeled()) {
1N/A /*
1N/A * do not print tnrhdb and tnrhtp if system is
1N/A * not configured with Trusted Extensions
1N/A */
1N/A if ((strcasecmp(maplist[i].database, "tnrhdb") == 0) ||
1N/A (strcasecmp(maplist[i].database, "tnrhtp") == 0))
1N/A continue;
1N/A }
1N/A (void) fprintf(stdout, "%-15s%-20s%s\n", maplist[i].database,
1N/A maplist[i].def_type, maplist[i].objectclass);
1N/A }
1N/A}
1N/A
1N/A/*
1N/A * set_key routine to handle user specified keys.
1N/A * A key can be of the form: attribute=value or value.
1N/A * A filter is constructed from a set of keys specified in
1N/A * the form (|(key1)(key2)...(keyn))
1N/A * It returns: NULL if no keys are defined or
1N/A * the keyfilter as constructed above.
1N/A */
1N/A
1N/Achar *
1N/Aset_keys(char **key, char *attrtype)
1N/A{
1N/A char *keyeq = NULL;
1N/A char *keyfilter = NULL;
1N/A int len, totlen = 1; /* Terminating NULL byte */
1N/A char *k, **karray;
1N/A char *tmpptr;
1N/A
1N/A if (!key || !key[0]) /* should never contain NULL string */
1N/A return (NULL);
1N/A
1N/A if (key[1]) {
1N/A totlen += 3;
1N/A /* Allocate memory for '(|)' */
1N/A MALLOC(keyfilter, totlen);
1N/A if (!keyfilter)
1N/A exit(2);
1N/A (void) snprintf(keyfilter, totlen, "(|");
1N/A }
1N/A
1N/A karray = key;
1N/A while ((k = *karray) != 0) {
1N/A keyeq = strchr(k, '=');
1N/A if (keyeq) {
1N/A /* make enough room for (%s) */
1N/A totlen += strlen(k) + 2;
1N/A } else {
1N/A /* make enough room for (%s=%s) */
1N/A totlen += strlen(attrtype) + strlen(k) + 3;
1N/A }
1N/A
1N/A len = keyfilter ? strlen(keyfilter) : 0;
1N/A
1N/A if (!(tmpptr = (char *)realloc(keyfilter, totlen))) {
1N/A if (keyfilter)
1N/A free(keyfilter);
1N/A (void) fprintf(stderr, gettext("out of memory\n"));
1N/A exit(2);
1N/A }
1N/A keyfilter = tmpptr;
1N/A
1N/A if (keyeq) {
1N/A (void) snprintf(keyfilter + len, totlen - len,
1N/A "(%s)", k);
1N/A } else {
1N/A (void) snprintf(keyfilter + len, totlen - len,
1N/A "(%s=%s)", attrtype, k);
1N/A }
1N/A karray++;
1N/A }
1N/A
1N/A if (key[1]) {
1N/A /* We allocated memory for this earlier */
1N/A (void) strlcat(keyfilter, ")", totlen);
1N/A }
1N/A
1N/A return (keyfilter);
1N/A}
1N/A
1N/A
1N/A/*
1N/A * A special set_key routine for to handle public keys.
1N/A * If the key starts with a digiti, view it as a user id.
1N/A * Otherwise, view it as a hostname.
1N/A * It returns: -1 no keys defined, 0 key defined but none for type
1N/A * specified, n>0 number of matches found.
1N/A */
1N/Aint
1N/Aset_keys_publickey(char **key, char *attrtype, int type, char **ret)
1N/A{
1N/A char *keyeq = NULL;
1N/A char *keyfilter = NULL;
1N/A char *pre_filter = NULL;
1N/A char *k, **karray;
1N/A int count = 0;
1N/A int len, totlen = 1; /* Terminating NULL byte */
1N/A char *tmpptr;
1N/A
1N/A if (!key || !key[0]) { /* should never contain NULL string */
1N/A *ret = NULL;
1N/A return (-1);
1N/A }
1N/A
1N/A karray = key;
1N/A while ((k = *karray) != 0) {
1N/A keyeq = strchr(k, '=');
1N/A if (keyeq) {
1N/A /* make enough room for (%s) */
1N/A totlen += strlen(k) + 2;
1N/A } else {
1N/A if ((type == 0 && isdigit(*k)) ||
1N/A /* user type keys */
1N/A (type == 1 && (!isdigit(*k)))) {
1N/A /* hosts type keys */
1N/A /* make enough room for (%s=%s) */
1N/A totlen += strlen(k) + strlen(attrtype) + 3;
1N/A } else {
1N/A karray++;
1N/A continue;
1N/A }
1N/A }
1N/A
1N/A len = pre_filter ? strlen(pre_filter) : 0;
1N/A
1N/A if (!(tmpptr = (char *)realloc(pre_filter, totlen))) {
1N/A if (pre_filter)
1N/A free(pre_filter);
1N/A (void) fprintf(stderr, gettext("out of memory\n"));
1N/A exit(2);
1N/A }
1N/A pre_filter = tmpptr;
1N/A
1N/A if (keyeq) {
1N/A (void) snprintf(pre_filter + len, totlen - len,
1N/A "(%s)", k);
1N/A } else {
1N/A (void) snprintf(pre_filter + len, totlen - len,
1N/A "(%s=%s)", attrtype, k);
1N/A }
1N/A karray++;
1N/A count++;
1N/A }
1N/A if (count > 1) {
1N/A len = strlen(pre_filter) + 4;
1N/A if (!(keyfilter = (char *)malloc(len))) {
1N/A (void) fprintf(stderr, gettext("out of memory\n"));
1N/A free(pre_filter);
1N/A exit(2);
1N/A }
1N/A (void) snprintf(keyfilter, len, "(|%s)", pre_filter);
1N/A free(pre_filter);
1N/A *ret = keyfilter;
1N/A } else
1N/A *ret = pre_filter;
1N/A return (count);
1N/A}
1N/A
1N/A/*
1N/A * publickey specific set_filter
1N/A * type 0 -> check for user publickeys
1N/A * type 1 -> check for hosts publickeys
1N/A */
1N/Achar *
1N/Aset_filter_publickey(char **key, char *database, int type, char **udata)
1N/A{
1N/A char *filter = NULL;
1N/A char *userdata;
1N/A char *keyfilter = NULL;
1N/A int rc;
1N/A int filterlen, udatalen;
1N/A short nomem = 0;
1N/A
1N/A if (!database || !udata) {
1N/A return (NULL);
1N/A }
1N/A
1N/A if (strcasecmp(database, maplist[PUBLICKEY].database) == SAME) {
1N/A rc = set_keys_publickey(key,
1N/A maplist[PUBLICKEY + type].def_type, type, &keyfilter);
1N/A switch (rc) {
1N/A case -1:
1N/A filterlen = strlen(maplist[PUBLICKEY].objectclass) + 13;
1N/A udatalen = 3;
1N/A MALLOC_FILTER_UDATA(filter, filterlen, userdata,
1N/A udatalen, nomem);
1N/A if (!nomem) {
1N/A (void) snprintf(filter, filterlen,
1N/A "objectclass=%s",
1N/A maplist[PUBLICKEY].objectclass);
1N/A (void) snprintf(userdata, udatalen, "%%s");
1N/A }
1N/A break;
1N/A case 0:
1N/A return (NULL);
1N/A default:
1N/A filterlen = strlen(maplist[PUBLICKEY].objectclass) +
1N/A strlen(keyfilter) + 18;
1N/A udatalen = strlen(keyfilter) + 8;
1N/A MALLOC_FILTER_UDATA(filter, filterlen, userdata,
1N/A udatalen, nomem);
1N/A if (!nomem) {
1N/A (void) snprintf(filter, filterlen,
1N/A "(&(objectclass=%s)%s)",
1N/A maplist[PUBLICKEY].objectclass, keyfilter);
1N/A (void) snprintf(userdata, udatalen,
1N/A "(&(%%s)%s)", keyfilter);
1N/A }
1N/A }
1N/A } else {
1N/A if ((keyfilter = set_keys(key, "cn")) == NULL) {
1N/A filterlen = 14;
1N/A udatalen = 3;
1N/A MALLOC_FILTER_UDATA(filter, filterlen, userdata,
1N/A udatalen, nomem);
1N/A if (!nomem) {
1N/A (void) snprintf(filter, filterlen,
1N/A "objectclass=*");
1N/A (void) snprintf(userdata, udatalen, "%%s");
1N/A }
1N/A } else {
1N/A filterlen = strlen(keyfilter) + 1;
1N/A udatalen = strlen(keyfilter) + 8;
1N/A MALLOC_FILTER_UDATA(filter, filterlen, userdata,
1N/A udatalen, nomem);
1N/A if (!nomem) {
1N/A (void) snprintf(filter, filterlen, "%s",
1N/A keyfilter);
1N/A (void) snprintf(userdata, udatalen,
1N/A "(&(%%s)%s)", keyfilter);
1N/A }
1N/A }
1N/A }
1N/A#ifdef DEBUG
1N/A (void) fprintf(stdout, "set_filter: filter=\"%s\"\n", filter);
1N/A (void) fprintf(stdout, "set_filter: userdata=\"%s\"\n", userdata);
1N/A#endif /* DEBUG */
1N/A if (keyfilter)
1N/A free(keyfilter);
1N/A if (nomem)
1N/A exit(2);
1N/A *udata = userdata;
1N/A return (filter);
1N/A}
1N/A
1N/A
1N/A/* generic set_filter, this function is not thread safe */
1N/Achar *
1N/Aset_filter(char **key, char *database, char **udata)
1N/A{
1N/A char *filter = NULL;
1N/A char *userdata = NULL;
1N/A char *keyfilter;
1N/A int i, filterlen, udatalen;
1N/A int rc, v2 = 1;
1N/A int dbpf, dbtp;
1N/A void **paramVal = NULL;
1N/A ns_ldap_error_t *errorp = NULL;
1N/A short nomem;
1N/A
1N/A if (!database || !udata) {
1N/A return (NULL);
1N/A }
1N/A
1N/A
1N/A /*
1N/A * Check for version of the profile the client is using
1N/A *
1N/A * For version 1 profiles we do use nisMap and nisObject schema
1N/A * for backward compatibility with Solaris 8 clients.
1N/A *
1N/A * For version 2 profiles we use automountMap and automount as
1N/A * default attributes (which can then be overridden in libsldap
1N/A * if schema mapping is configured in the profile).
1N/A *
1N/A * If profile version is not available, use version 2 as default.
1N/A */
1N/A rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, &paramVal, &errorp);
1N/A if (rc != NS_LDAP_SUCCESS || !paramVal || !*paramVal) {
1N/A /* should print a message here: using v2 defaults */
1N/A (void) __ns_ldap_freeError(&errorp);
1N/A } else {
1N/A if (strcasecmp(*paramVal, NS_LDAP_VERSION_1) == 0)
1N/A v2 = 0;
1N/A (void) __ns_ldap_freeParam(&paramVal);
1N/A }
1N/A
1N/A /*
1N/A * starts at 2 to skip over publickey databases.
1N/A * These databases are handled separately.
1N/A */
1N/A for (i = 2; maplist[i].database != NULL; i++) {
1N/A if (strcasecmp(database, maplist[i].database) == SAME) {
1N/A dbpf = 0, dbtp = 0;
1N/A if (strcasecmp(database, "prof_attr") == 0)
1N/A dbpf = 1;
1N/A else if (strcasecmp(database, "tnrhtp") == 0)
1N/A dbtp = 1;
1N/A if ((keyfilter = set_keys(key, maplist[i].def_type))
1N/A == NULL) {
1N/A filterlen = strlen(maplist[i].objectclass);
1N/A udatalen = 3;
1N/A if (dbpf)
1N/A filterlen += strlen(PROF_ATTR_FILTER)
1N/A + 1;
1N/A else if (dbtp)
1N/A filterlen += strlen(TNRHTP_FILTER) + 1;
1N/A else
1N/A filterlen += OC_FLEN;
1N/A
1N/A MALLOC_FILTER_UDATA(filter, filterlen, userdata,
1N/A udatalen, nomem);
1N/A if (nomem)
1N/A goto done;
1N/A if (dbpf)
1N/A (void) snprintf(filter, filterlen,
1N/A PROF_ATTR_FILTER, "");
1N/A else if (dbtp)
1N/A (void) snprintf(filter, filterlen,
1N/A TNRHTP_FILTER, "");
1N/A else
1N/A (void) snprintf(filter, filterlen,
1N/A OC_FILTER,
1N/A maplist[i].objectclass);
1N/A
1N/A (void) snprintf(userdata, udatalen, "%%s");
1N/A } else {
1N/A filterlen = strlen(maplist[i].objectclass) +
1N/A strlen(keyfilter);
1N/A if (dbpf)
1N/A filterlen += strlen(PROF_ATTR_FILTER)
1N/A + 1;
1N/A else if (dbtp)
1N/A filterlen += strlen(TNRHTP_FILTER) + 1;
1N/A else
1N/A filterlen += OC_FLEN2;
1N/A
1N/A udatalen = strlen(keyfilter) + 8;
1N/A MALLOC_FILTER_UDATA(filter, filterlen, userdata,
1N/A udatalen, nomem);
1N/A if (nomem)
1N/A goto done;
1N/A if (dbpf)
1N/A (void) snprintf(filter, filterlen,
1N/A PROF_ATTR_FILTER, keyfilter);
1N/A else if (dbtp)
1N/A (void) snprintf(filter, filterlen,
1N/A TNRHTP_FILTER, keyfilter);
1N/A else
1N/A (void) snprintf(filter, filterlen,
1N/A OC_FILTER2,
1N/A maplist[i].objectclass, keyfilter);
1N/A
1N/A (void) snprintf(userdata, udatalen,
1N/A "(&(%%s)%s)", keyfilter);
1N/A }
1N/A goto done;
1N/A }
1N/A }
1N/A
1N/A /* special cases for automounter and other services */
1N/A
1N/A /* auto_* services */
1N/A if (strncasecmp(database, "auto_", 5) == SAME) {
1N/A if (v2) {
1N/A if ((keyfilter = set_keys(key, "automountKey"))
1N/A != NULL) {
1N/A filterlen = strlen(keyfilter) + 27;
1N/A udatalen = strlen(keyfilter) + 8;
1N/A MALLOC_FILTER_UDATA(filter, filterlen,
1N/A userdata, udatalen, nomem);
1N/A if (!nomem) {
1N/A (void) snprintf(filter, filterlen,
1N/A "(&(objectclass=automount)%s)",
1N/A keyfilter);
1N/A (void) snprintf(userdata, udatalen,
1N/A "(&(%%s)%s)", keyfilter);
1N/A }
1N/A } else {
1N/A filterlen = 22;
1N/A udatalen = 3;
1N/A MALLOC_FILTER_UDATA(filter, filterlen,
1N/A userdata, udatalen, nomem);
1N/A if (!nomem) {
1N/A (void) strlcpy(filter,
1N/A "objectclass=automount", filterlen);
1N/A (void) strlcpy(userdata, "%s",
1N/A udatalen);
1N/A }
1N/A }
1N/A } else {
1N/A if ((keyfilter = set_keys(key, "cn")) != NULL) {
1N/A filterlen = strlen(keyfilter) + 27;
1N/A udatalen = strlen(keyfilter) + 8;
1N/A MALLOC_FILTER_UDATA(filter, filterlen,
1N/A userdata, udatalen, nomem);
1N/A if (!nomem) {
1N/A (void) snprintf(filter, filterlen,
1N/A "(&(objectclass=nisObject)%s)",
1N/A keyfilter);
1N/A (void) snprintf(userdata, udatalen,
1N/A "(&(%%s)%s)", keyfilter);
1N/A }
1N/A } else {
1N/A filterlen = 22;
1N/A udatalen = 3;
1N/A MALLOC_FILTER_UDATA(filter, filterlen,
1N/A userdata, udatalen, nomem);
1N/A if (!nomem) {
1N/A (void) strlcpy(filter,
1N/A "objectclass=nisObject", filterlen);
1N/A (void) strlcpy(userdata, "%s",
1N/A udatalen);
1N/A }
1N/A }
1N/A }
1N/A goto done;
1N/A }
1N/A
1N/A /* automount service */
1N/A if (strcasecmp(database, "automount") == SAME) {
1N/A if (v2) {
1N/A if ((keyfilter = set_keys(key, "automountMapName"))
1N/A != NULL) {
1N/A filterlen = strlen(keyfilter) + 30;
1N/A udatalen = strlen(keyfilter) + 8;
1N/A MALLOC_FILTER_UDATA(filter, filterlen,
1N/A userdata, udatalen, nomem);
1N/A if (!nomem) {
1N/A (void) snprintf(filter, filterlen,
1N/A "(&(objectclass=automountMap)%s)",
1N/A keyfilter);
1N/A (void) snprintf(userdata, udatalen,
1N/A "(&(%%s)%s)", keyfilter);
1N/A }
1N/A } else {
1N/A filterlen = 25;
1N/A udatalen = 3;
1N/A MALLOC_FILTER_UDATA(filter, filterlen,
1N/A userdata, udatalen, nomem);
1N/A if (!nomem) {
1N/A (void) strlcpy(filter,
1N/A "objectclass=automountMap",
1N/A filterlen);
1N/A (void) strlcpy(userdata, "%s",
1N/A udatalen);
1N/A }
1N/A }
1N/A } else {
1N/A if ((keyfilter = set_keys(key, "nisMapName"))
1N/A != NULL) {
1N/A filterlen = strlen(keyfilter) + 24;
1N/A udatalen = strlen(keyfilter) + 8;
1N/A MALLOC_FILTER_UDATA(filter, filterlen,
1N/A userdata, udatalen, nomem);
1N/A if (!nomem) {
1N/A (void) snprintf(filter, filterlen,
1N/A "(&(objectclass=nisMap)%s)",
1N/A keyfilter);
1N/A (void) snprintf(userdata, udatalen,
1N/A "(&(%%s)%s)", keyfilter);
1N/A }
1N/A } else {
1N/A filterlen = 19;
1N/A udatalen = 3;
1N/A MALLOC_FILTER_UDATA(filter, filterlen,
1N/A userdata, udatalen, nomem);
1N/A if (!nomem) {
1N/A (void) strlcpy(filter,
1N/A "objectclass=nisMap", filterlen);
1N/A (void) strlcpy(userdata, "%s",
1N/A udatalen);
1N/A }
1N/A }
1N/A }
1N/A goto done;
1N/A }
1N/A
1N/A /* other services (catch all) */
1N/A if ((keyfilter = set_keys(key, "cn")) == NULL) {
1N/A filterlen = 14;
1N/A udatalen = 3;
1N/A MALLOC_FILTER_UDATA(filter, filterlen, userdata, udatalen,
1N/A nomem);
1N/A if (!nomem) {
1N/A (void) snprintf(filter, filterlen, "objectclass=*");
1N/A (void) strlcpy(userdata, "%s", udatalen);
1N/A }
1N/A } else {
1N/A filterlen = strlen(keyfilter) + 1;
1N/A udatalen = strlen(keyfilter) + 8;
1N/A MALLOC_FILTER_UDATA(filter, filterlen, userdata, udatalen,
1N/A nomem);
1N/A if (!nomem) {
1N/A (void) snprintf(filter, filterlen, "%s", keyfilter);
1N/A (void) snprintf(userdata, udatalen, "(&(%%s)%s)",
1N/A keyfilter);
1N/A }
1N/A }
1N/A
1N/Adone:
1N/A#ifdef DEBUG
1N/A (void) fprintf(stdout, "set_filter: filter=\"%s\"\n", filter);
1N/A (void) fprintf(stdout, "set_filter: userdata=\"%s\"\n", userdata);
1N/A#endif /* DEBUG */
1N/A if (keyfilter)
1N/A free(keyfilter);
1N/A if (nomem)
1N/A exit(2);
1N/A *udata = userdata;
1N/A return (filter);
1N/A}