summaryrefslogtreecommitdiff
path: root/usr/src/lib/libnisdb/ldap_parse.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libnisdb/ldap_parse.c
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libnisdb/ldap_parse.c')
-rw-r--r--usr/src/lib/libnisdb/ldap_parse.c617
1 files changed, 617 insertions, 0 deletions
diff --git a/usr/src/lib/libnisdb/ldap_parse.c b/usr/src/lib/libnisdb/ldap_parse.c
new file mode 100644
index 0000000000..20a1b4b1c9
--- /dev/null
+++ b/usr/src/lib/libnisdb/ldap_parse.c
@@ -0,0 +1,617 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <deflt.h>
+#include <limits.h>
+
+#include "ldap_parse.h"
+#include "ldap_glob.h"
+#include "ldap_attr.h"
+#include "ldap_util.h"
+#include "ldap_map.h"
+#include "ldap_ruleval.h"
+#include "nis_parse_ldap_conf.h"
+
+int yp2ldap = 0;
+/*
+ * List of mapping structures in original (i.e., as in config file) order.
+ * Lined on the 'seqNext' field.
+ */
+__nis_table_mapping_t *ldapMappingSeq = 0;
+
+/*
+ * Call the parser for the config file 'ldapConfFile', and command line
+ * attribute settings per 'ldapCLA'.
+ *
+ * Returns
+ * 0 Success
+ * -1 Config file stat/open or parse error
+ * 1 No mapping should be used.
+ */
+int
+parseConfig(char **ldapCLA, char *ldapConfFile) {
+ int ret;
+
+ /*
+ * Establish defaults for ldapDBTableMapping, so that we have
+ * valid values even if there's no mapping config to parse.
+ */
+ ldapDBTableMapping.initTtlLo = (3600-1800);
+ ldapDBTableMapping.initTtlHi = (3600+1800);
+ ldapDBTableMapping.ttl = 3600;
+ ldapDBTableMapping.enumExpire = 0;
+ ldapDBTableMapping.fromLDAP = FALSE;
+ ldapDBTableMapping.toLDAP = FALSE;
+ ldapDBTableMapping.expire = 0;
+
+ ret = parse_ldap_migration((const char **)ldapCLA, ldapConfFile);
+
+ return (ret);
+}
+
+/*
+ * Convert the linked list of __nis_table_mapping_t's (produced by the
+ * attribute parser) to the 'ldapMappingList', keyed on the objPath.
+ *
+ * Once this function has returned, the 'tlist' is invalid, and must
+ * not be used in any way.
+ */
+int
+linked2hash(__nis_table_mapping_t *tlist) {
+ __nis_hash_table_mt dbids;
+ __nis_table_mapping_t *t, *told, *x, **seqNext;
+ __nis_object_dn_t *o, *to;
+ char *myself = "linked2hash";
+#ifdef NISDB_LDAP_DEBUG
+ char *selectDbid = getenv("NISLDAPSELECTDBID");
+ char **sdi, *s;
+ int i, nsdi;
+#endif /* NISDB_LDAP_DEBUG */
+
+
+ if (tlist == 0)
+ return (0);
+
+ /* proxyInfo.default_nis_domain must end in a dot */
+ {
+ int len = slen(proxyInfo.default_nis_domain);
+
+ if (len > 0 && proxyInfo.default_nis_domain[len-1] != '.') {
+ char *domain = am(myself, len+2);
+
+ (void) memcpy(domain, proxyInfo.default_nis_domain,
+ len);
+ domain[len] = '.';
+ domain[len+1] = '\0';
+ sfree(proxyInfo.default_nis_domain);
+ proxyInfo.default_nis_domain = domain;
+ }
+ }
+
+#ifdef NISDB_LDAP_DEBUG
+ for (nsdi = 0, s = selectDbid; s != 0 && *s != '\0'; s++) {
+ if (*s != ' ') {
+ nsdi++;
+ while (*s != ' ' && *s != '\0')
+ s++;
+ if (*s == '\0')
+ break;
+ }
+ }
+ if (nsdi > 0) {
+ sdi = am(myself, nsdi * sizeof (sdi[0]));
+ if (sdi == 0)
+ logmsg(MSG_NOTIMECHECK, LOG_WARNING,
+ "%s: Memory alloc failure for dbId selection",
+ myself);
+ else {
+ for (i = 0, s = selectDbid; *s != '\0'; s++) {
+ if (*s != ' ') {
+ sdi[i++] = selectDbid;
+ while (*s != ' ' && *s != '\0')
+ s++;
+ if (*s != '\0') {
+ *s = '\0';
+ s++;
+ } else
+ break;
+ selectDbid = s;
+ }
+ }
+ }
+ }
+#endif /* NISDB_LDAP_DEBUG */
+
+ __nis_init_hash_table(&dbids, 0);
+
+ seqNext = &ldapMappingSeq;
+ for (t = tlist; t != 0; t = told) {
+ int len;
+
+#ifdef NISDB_LDAP_DEBUG
+ /*
+ * If the dbId doesn't match 'selectDbid', skip this
+ * mapping. Re-insert on 'tlist', in order to keep memory
+ * leak checking happy. Note that 'tlist' may end up pointing
+ * into the real mapping list, so it shouldn't be used once
+ * this routine has been called.
+ */
+ if (nsdi > 0) {
+ for (i = 0; i < nsdi; i++) {
+ if (strcmp(sdi[i], t->dbId) == 0)
+ break;
+ }
+ if (i >= nsdi) {
+ told = t->next;
+ if (tlist != t)
+ t->next = tlist;
+ else
+ t->next = 0;
+ tlist = t;
+ continue;
+ }
+ }
+#endif /* NISDB_LDAP_DEBUG */
+
+ told = t->next;
+ t->next = 0;
+
+ /* Make sure t->item.name is set correctly */
+ if (t->item.name == 0)
+ t->item.name = t->dbId;
+
+ /* Remove leading dot in object name, if any */
+ len = slen(t->objName);
+ while (len > 0 && t->objName[0] == '.') {
+ (void) memmove(t->objName, &t->objName[1], len);
+ len -= 1;
+ }
+
+ /*
+ * Initialize the object path, which is what we'll
+ * rehash on.
+ */
+ if (yp2ldap) {
+ t->objPath = internal_table_name(t->objName,
+ t->objPath);
+ if (!t->objPath) {
+ logmsg(MSG_NOTIMECHECK, LOG_ERR,
+ "%s: Failed to obtain internal table name for \"%s\"",
+ myself, t->objName);
+ return (-1);
+ }
+ } else {
+ t->objPath = am(myself, len + MAXPATHLEN + 1);
+ if (t->objPath == 0)
+ return (-1);
+ if (internal_table_name(t->objName,
+ t->objPath) == 0) {
+ logmsg(MSG_NOTIMECHECK, LOG_ERR,
+ "%s: Failed to obtain internal table name for \"%s\"",
+ myself, t->objName);
+ return (-1);
+ }
+ }
+
+ /*
+ * Initialize the column name array.
+ */
+ if (!yp2ldap) {
+ if (setColumnsDuringConfig && setColumnNames(t)) {
+ logmsg(MSG_NOTIMECHECK, LOG_ERR,
+ "%s: Unable to find column names for \"%s\"",
+ myself, NIL(t->objName));
+ return (-1);
+ }
+ }
+
+ /*
+ * If there are multiple mapping target containers, make
+ * each one into it's own mapping structure. They can all
+ * be minimal copies (i.e., share pointers to sub-structures
+ * other than the objectDN).
+ *
+ * If objectDN is NULL, we will never use this structure.
+ * In order to allow the rest of the mapping code to assume
+ * objectDN != NULL, skip the mapping (even if x == t).
+ */
+ for (o = to = t->objectDN; o != 0; o = o->next) {
+ __nis_table_mapping_t *p;
+
+ if (o == to) {
+ x = t;
+ /*
+ * Only insert the first mapping for an
+ * object on the sequential list.
+ */
+ *seqNext = t;
+ t->seqNext = 0;
+ seqNext = (__nis_table_mapping_t **)&t->seqNext;
+ } else {
+ x = am(myself, sizeof (*x));
+ if (x == 0) {
+ /*
+ * This happens during rpc.nisd
+ * initialization, and it's an
+ * unrecoverable disaster, so don't
+ * bother cleaning up.
+ */
+ return (-1);
+ }
+ memcpy(x, t, sizeof (*x));
+ x->objectDN = o;
+ x->next = 0;
+ }
+
+ /*
+ * If x->objectDN->write.base is NULL, clone it from
+ * x->objectDN->read.base.
+ */
+ if (x->objectDN->write.scope != LDAP_SCOPE_UNKNOWN) {
+ if (x->objectDN->write.base == 0 &&
+ x->objectDN->read.base != 0) {
+ x->objectDN->write.base =
+ sdup(myself, T,
+ x->objectDN->read.base);
+ if (x->objectDN->write.base == 0)
+ return (-1);
+ }
+ if (x->objectDN->write.attrs == 0 &&
+ x->objectDN->read.attrs != 0) {
+ x->objectDN->write.attrs =
+ sdup(myself, T,
+ x->objectDN->read.attrs);
+ if (x->objectDN->write.attrs == 0)
+ return (-1);
+ }
+ }
+
+ if (o != to) {
+ /* Insert last on the 't->next' list */
+ for (p = t; p->next != 0; p = p->next);
+ p->next = x;
+ }
+ }
+
+ /* Insert on dbid hash list */
+ if (t->objectDN != 0 && !__nis_insert_item_mt(t, &dbids, 0)) {
+ logmsg(MSG_NOTIMECHECK, LOG_ERR,
+ "%s: Error inserting mapping for \"%s\" on hash list",
+ myself, NIL(t->objName));
+#ifdef NISDB_LDAP_DEBUG
+ abort();
+#endif /* NISDB_LDAP_DEBUG */
+ return (-1);
+ }
+ }
+
+ /*
+ * dbids2objs() will remove the entries on 'dbids', so no need
+ * to clean up that list from this function.
+ */
+ return (dbids2objs(&dbids, &ldapMappingList));
+}
+
+int
+dbids2objs(__nis_hash_table_mt *dbids, __nis_hash_table_mt *objs) {
+ __nis_table_mapping_t *t, *o;
+ char *myself = "dbids2objs";
+
+
+ while ((t = __nis_pop_item_mt(dbids)) != 0) {
+ /* Previous entry for this object ? */
+ o = __nis_find_item_mt(t->objPath, objs, -1, 0);
+ if (o != 0) {
+ __nis_table_mapping_t *p = o;
+ /*
+ * Mapping already exists, so this is an alternate.
+ * Find the end of the list of any previous alt's,
+ * and insert there.
+ */
+ while (p->next != 0) {
+ p = p->next;
+ }
+ p->next = t;
+ if (!__nis_release_item(o, objs, -1)) {
+ logmsg(MSG_NOTIMECHECK, LOG_ERR,
+ "%s: __nis_release_item error",
+ myself);
+ return (-1);
+ }
+ } else {
+ t->item.name = t->objPath;
+ if (!__nis_insert_item_mt(t, objs, 0)) {
+ logmsg(MSG_NOTIMECHECK, LOG_ERR,
+ "%s: __nis_insert_item error",
+ myself);
+ return (-1);
+ }
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * internal_table_name()
+ *
+ * Removes the local domain part from a fully qualified name
+ * to create the internal table name for an object. These tables are
+ * stored in /var/nis/<hostname>
+ *
+ * Imported from rpc.nisd/nisdb.c.
+ */
+char *
+internal_table_name(nis_name name, char *res)
+{
+ char *s, *t;
+ int i, j;
+
+ if (yp2ldap) {
+ if (name == NULL)
+ return (NULL);
+ res = s_strndup(name, strlen(name));
+ if (res == NULL)
+ return (NULL);
+ return (res);
+ }
+
+ if (res == NULL)
+ return (NULL);
+ /* pointer at the first character of the table name */
+ s = relative_name(name);
+
+ /*
+ * If s == NULL then either this is a request for a lookup
+ * in our parents namespace (ILLEGAL), or we're the root
+ * server and this is a lookup in our namespace.
+ */
+ if (s) {
+ strcpy(res, nis_data(s));
+ free((void *)s);
+ } else if (nis_dir_cmp(name, __nis_rpc_domain()) == SAME_NAME) {
+ strcpy(res, nis_data("ROOT_DIR"));
+ } else {
+ return (NULL);
+ }
+
+ t = strrchr(res, '/');
+ if (t)
+ t++; /* Point past the slash */
+ /* Strip off the quotes if they were used here. */
+ if (t[0] == '"') {
+ /* Check for simply a quoted quote. */
+ if (t[1] != '"') {
+ j = strlen(t);
+ /* shift string left by one */
+ for (i = 0; i < j; i++)
+ t[i] = t[i+1];
+ t[j-2] = '\0'; /* Trounce trailing dquote */
+ }
+ }
+ /*
+ * OK so now we have the unique name for the table.
+ * At this point we can fix it up to match local
+ * file system conventions if we so desire. Since it
+ * is only used in this form by _this_ server we can
+ * mangle it any way we want, as long as we are consistent
+ * about it. :-)
+ */
+ __make_legal(res);
+ return (res);
+}
+
+/*
+ * SYSTEM DEPENDENT
+ *
+ * This function makes the table name "legal" for the underlying file system.
+ *
+ * Imported from rpc.nisd/nisdb.c.
+ */
+void
+__make_legal(char *s)
+{
+ while (*s) {
+ if (isupper(*s))
+ *s = tolower(*s);
+ s++;
+ }
+}
+
+/*
+ * relative_name()
+ * This internal function will remove from the NIS name, the domain
+ * name of the current server, this will leave the unique part in
+ * the name this becomes the "internal" version of the name. If this
+ * function returns NULL then the name we were given to resolve is
+ * bad somehow.
+ *
+ * A dynamically-allocated string is returned.
+ *
+ * Imported from rpc.nisd/nis_log_common.c
+ */
+
+nis_name
+relative_name(s)
+ char *s; /* string with the name in it. */
+{
+ char *d;
+ char *buf;
+ int dl, sl;
+ name_pos p;
+
+ if (s == NULL)
+ return (NULL);
+
+ d = __nis_rpc_domain();
+ if (d == NULL)
+ return (NULL);
+ dl = strlen(d); /* _always dot terminated_ */
+
+ buf = strdup(s);
+ if (buf == NULL)
+ return (NULL);
+ strcpy(buf, s); /* Make a private copy of 's' */
+ sl = strlen(buf);
+
+ if (dl == 1) { /* We're the '.' directory */
+ buf[sl-1] = '\0'; /* Lose the 'dot' */
+ return (buf);
+ }
+
+ p = nis_dir_cmp(buf, d);
+
+ /* 's' is above 'd' in the tree */
+ if ((p == HIGHER_NAME) || (p == NOT_SEQUENTIAL) || (p == SAME_NAME)) {
+ free(buf);
+ return (NULL);
+ }
+
+ /* Insert a NUL where the domain name starts in the string */
+ buf[(sl - dl) - 1] = '\0';
+
+ /* Don't return a zero length name */
+ if (buf[0] == '\0') {
+ free((void *)buf);
+ return (NULL);
+ }
+
+ return (buf);
+}
+
+/*
+ * Wrapper for internal_table_name() that allocates a large enough
+ * buffer for the internal name. Return value must be freed by caller.
+ * If the input 'name' is NULL, the name of the root directory table
+ * is returned.
+ */
+char *
+internalTableName(char *name) {
+ char *buf, *res;
+ char *myself = "internalTableName";
+
+ buf = (char *)am(myself, MAXPATHLEN + NIS_MAXNAMELEN + 1);
+ if (buf == 0)
+ return (0);
+
+ if (name == 0) {
+ (void) memcpy(buf, ROOTDIRFILE, slen(ROOTDIRFILE));
+ return (buf);
+ }
+
+ res = internal_table_name(name, buf);
+ if (res != buf) {
+ sfree(buf);
+ buf = 0;
+ }
+
+ return (buf);
+}
+
+/*
+ * Return the object mapping for the object indicated either by the
+ * internal DB name ('intNameArg'; preferred), or the FQ object name
+ * 'name'. If 'asObj' is non-zero, the caller is interested in the
+ * object mapping proper, not a mapping of table entries. Optionally,
+ * also indicate if the object is mapped from (read) or to (write) LDAP.
+ *
+ * Note that there may be more than one mapping of the appropriate type.
+ * Use the selectTableMapping() function in ldap_map.c to get all
+ * alternatives. However, the function below works as a short-cut if:
+ *
+ * You only want an indication that _a_ mapping of the desired
+ * type exists, or
+ *
+ * You want the non-objectDN information for an object-mapping
+ * proper (i.e., _not_ the mapping for entries in a table).
+ */
+__nis_table_mapping_t *
+getObjMapping(char *name, char *intNameArg, int asObj,
+ int *doRead, int *doWrite) {
+ __nis_table_mapping_t *t, *x;
+ char *intName;
+ int freeIntName = 0, rd, wr;
+
+ if (doRead != 0)
+ *doRead = 0;
+ if (doWrite != 0)
+ *doWrite = 0;
+
+ if (intNameArg == 0) {
+ if (name == 0)
+ return (0);
+ intName = internalTableName(name);
+ if (intName == 0)
+ return (0);
+ freeIntName = 1;
+ } else {
+ intName = intNameArg;
+ }
+
+ t = __nis_find_item_mt(intName, &ldapMappingList, 0, 0);
+ if (t == 0) {
+ if (freeIntName)
+ sfree(intName);
+ return (0);
+ }
+
+ rd = wr = 0;
+ for (x = t; x != 0; x = x->next) {
+ /*
+ * If we're looking for an object mapping, and this
+ * one's for entries in a table, skip it.
+ */
+ if (asObj && x->objType == NIS_TABLE_OBJ &&
+ x->numColumns > 0)
+ continue;
+ /* Check if we should read/write */
+ if (x->objectDN->read.scope != LDAP_SCOPE_UNKNOWN)
+ rd++;
+ if (x->objectDN->write.scope != LDAP_SCOPE_UNKNOWN)
+ wr++;
+ }
+
+ if (doRead != 0)
+ *doRead = (rd > 0) ? 1 : 0;
+ if (doWrite != 0)
+ *doWrite = (wr > 0) ? 1 : 0;
+
+ if (freeIntName)
+ sfree(intName);
+
+ return (x);
+}