/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #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/ * * 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) { 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); }