diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libnisdb/ldap_parse.c | |
download | illumos-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.c | 617 |
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); +} |