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/nis_parse_ldap_util.c | |
download | illumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libnisdb/nis_parse_ldap_util.c')
-rw-r--r-- | usr/src/lib/libnisdb/nis_parse_ldap_util.c | 2689 |
1 files changed, 2689 insertions, 0 deletions
diff --git a/usr/src/lib/libnisdb/nis_parse_ldap_util.c b/usr/src/lib/libnisdb/nis_parse_ldap_util.c new file mode 100644 index 0000000000..617d4bb183 --- /dev/null +++ b/usr/src/lib/libnisdb/nis_parse_ldap_util.c @@ -0,0 +1,2689 @@ +/* + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <locale.h> +#include <lber.h> +#include <ldap.h> +#include <syslog.h> +#include <dlfcn.h> /* for dynamic loading only */ + +#include "ldap_parse.h" +#include "nis_parse_ldap_conf.h" +#include "nis_parse_ldap_err.h" +#include "ldap_util.h" +#include "ldap_util.h" + +void append_dot(char **str); +void append_comma(char **str); +bool_t make_full_dn(char **dn, const char *base); +bool_t make_fqdn(__nis_object_dn_t *dn, const char *base); +char *get_default_ldap_base(const char *domain); +bool_t add_domain(char **objName, const char *domain); +bool_t add_column(__nis_table_mapping_t *t, const char *col_name); +__nis_mapping_rule_t **dup_mapping_rules( + __nis_mapping_rule_t **rules, int n_rules); +__nis_mapping_rule_t *dup_mapping_rule( + __nis_mapping_rule_t *in); +void *s_malloc(size_t size); +__nis_mapping_format_t *dup_format_mapping( + __nis_mapping_format_t *in); +bool_t dup_mapping_element(__nis_mapping_element_t *in, + __nis_mapping_element_t *out); + +extern FILE *cons; + +/* + * FUNCTION: free_parse_structs + * + * Release the resources in parse results + * + */ + +void +free_parse_structs() +{ + __nis_table_mapping_t *t; + __nis_table_mapping_t *t1; + + free_proxy_info(&proxyInfo); + for (t = ldapTableMapping; t != NULL; t = t1) { + t1 = t->next; + free_table_mapping(t); + } + ldapTableMapping = NULL; +} + +/* + * FUNCTION: initialize_parse_structs + * + * Initialize fields to unset values + * + * INPUT: __nis_ldap_proxy_info, __nis_config_t + * and __nisdb_table_mapping_t structures + */ + +void +initialize_parse_structs( + __nis_ldap_proxy_info *proxy_info, + __nis_config_t *config_info, + __nisdb_table_mapping_t *table_info) +{ + proxy_info->default_servers = NULL; + proxy_info->auth_method = (auth_method_t)NO_VALUE_SET; + proxy_info->tls_method = (tls_method_t)NO_VALUE_SET; + proxy_info->tls_cert_db = NULL; + proxy_info->default_search_base = NULL; + proxy_info->proxy_dn = NULL; + proxy_info->proxy_passwd = NULL; + proxy_info->default_nis_domain = NULL; + proxy_info->bind_timeout.tv_sec = (time_t)NO_VALUE_SET; + proxy_info->bind_timeout.tv_usec = 0; + proxy_info->search_timeout.tv_sec = (time_t)NO_VALUE_SET; + proxy_info->search_timeout.tv_usec = 0; + proxy_info->modify_timeout.tv_sec = (time_t)NO_VALUE_SET; + proxy_info->modify_timeout.tv_usec = 0; + proxy_info->add_timeout.tv_sec = (time_t)NO_VALUE_SET; + proxy_info->add_timeout.tv_usec = 0; + proxy_info->delete_timeout.tv_sec = (time_t)NO_VALUE_SET; + proxy_info->delete_timeout.tv_usec = 0; + proxy_info->search_time_limit = (int)NO_VALUE_SET; + proxy_info->search_size_limit = (int)NO_VALUE_SET; + proxy_info->follow_referral = (follow_referral_t)NO_VALUE_SET; + + + config_info->initialUpdate = (__nis_initial_update_t)NO_VALUE_SET; + config_info->threadCreationError = + (__nis_thread_creation_error_t)NO_VALUE_SET; + config_info->threadCreationErrorTimeout.attempts = NO_VALUE_SET; + config_info->threadCreationErrorTimeout.timeout = (time_t)NO_VALUE_SET; + config_info->dumpError = (__nis_dump_error_t)NO_VALUE_SET; + config_info->dumpErrorTimeout.attempts = NO_VALUE_SET; + config_info->dumpErrorTimeout.timeout = (time_t)NO_VALUE_SET; + config_info->resyncService = (__nis_resync_service_t)NO_VALUE_SET; + config_info->updateBatching = (__nis_update_batching_t)NO_VALUE_SET; + config_info->updateBatchingTimeout.timeout = (time_t)NO_VALUE_SET; + config_info->numberOfServiceThreads = (int)NO_VALUE_SET; + config_info->emulate_yp = (int)NO_VALUE_SET; + config_info->maxRPCRecordSize = (int)NO_VALUE_SET; + + table_info->retrieveError = (__nis_retrieve_error_t)NO_VALUE_SET; + table_info->retrieveErrorRetry.attempts = NO_VALUE_SET; + table_info->retrieveErrorRetry.timeout = (time_t)NO_VALUE_SET; + table_info->storeError = (__nis_store_error_t)NO_VALUE_SET; + table_info->storeErrorRetry.attempts = NO_VALUE_SET; + table_info->storeErrorRetry.timeout = (time_t)NO_VALUE_SET; + table_info->refreshError = (__nis_refresh_error_t)NO_VALUE_SET; + table_info->refreshErrorRetry.attempts = NO_VALUE_SET; + table_info->refreshErrorRetry.timeout = (time_t)NO_VALUE_SET; + table_info->matchFetch = (__nis_match_fetch_t)NO_VALUE_SET; +} + +/* + * FUNCTION: free_mapping_rule + * + * Frees __nis_mapping_rule_t + * + * INPUT: __nis_mapping_rule_t + */ + +void +free_mapping_rule(__nis_mapping_rule_t *rule) +{ + int i; + __nis_mapping_rlhs_t *r; + + if (rule != NULL) { + r = &rule->lhs; + for (i = 0; i < r->numElements; i++) + free_mapping_element(&r->element[i]); + if (r->element != NULL) + free(r->element); + + r = &rule->rhs; + for (i = 0; i < r->numElements; i++) + free_mapping_element(&r->element[i]); + if (r->element != NULL) + free(r->element); + + free(rule); + } +} + +/* + * FUNCTION: free_mapping_element + * + * Frees __nis_mapping_element_t + * + * INPUT: __nis_mapping_element_t + */ + +void +free_mapping_element(__nis_mapping_element_t *e) +{ + int i; + + if (e == NULL) + return; + + switch (e->type) { + case me_item: + free_mapping_item(&e->element.item); + break; + case me_print: + if (e->element.print.fmt != NULL) + free_mapping_format(e->element.print.fmt); + e->element.print.fmt = NULL; + for (i = 0; i < e->element.print.numSubElements; i++) + free_mapping_sub_element( + &e->element.print.subElement[i]); + e->element.print.numSubElements = 0; + if (e->element.print.subElement != NULL) + free(e->element.print.subElement); + e->element.print.subElement = NULL; + break; + case me_split: + free_mapping_item(&e->element.split.item); + break; + case me_match: + if (e->element.match.fmt != NULL) + free_mapping_format(e->element.match.fmt); + e->element.match.fmt = NULL; + for (i = 0; i < e->element.match.numItems; i++) + free_mapping_item(&e->element.match.item[i]); + e->element.match.numItems = 0; + if (e->element.match.item != NULL) + free(e->element.match.item); + e->element.match.item = NULL; + break; + case me_extract: + if (e->element.extract.fmt != NULL) + free_mapping_format(e->element.extract.fmt); + e->element.extract.fmt = NULL; + free_mapping_item(&e->element.extract.item); + break; + } + e = NULL; +} + +/* + * FUNCTION: free_table_mapping + * + * Frees __nis_table_mapping_t + * + * INPUT: __nis_table_mapping_t + */ + +/* + * free_table_mapping does not remove the table mapping from + * its hashed list + */ + +void +free_table_mapping(__nis_table_mapping_t *mapping) +{ + int i; + + if (mapping == NULL) + return; + + if (mapping->dbId != NULL) + free(mapping->dbId); + mapping->dbId = NULL; + + if (mapping->objName != NULL) + free(mapping->objName); + mapping->objName = NULL; + + for (i = 0; i < mapping->index.numIndexes; i++) { + free(mapping->index.name[i]); + free_mapping_format(mapping->index.value[i]); + } + + if (mapping->index.name != NULL) + free(mapping->index.name); + mapping->index.name = NULL; + + if (mapping->index.value != NULL) + free(mapping->index.value); + mapping->index.value = NULL; + + mapping->index.numIndexes = 0; + + if (mapping->column != NULL) { + for (i = 0; i < mapping->numColumns; i++) { + free(mapping->column[i]); + } + mapping->numColumns = 0; + free(mapping->column); + mapping->column = NULL; + } + + if (mapping->commentChar != NULL) + mapping->commentChar = NULL; + + if (mapping->objectDN != NULL) + free_object_dn(mapping->objectDN); + mapping->objectDN = NULL; + + if (mapping->separatorStr != NULL) + mapping->separatorStr = NULL; + + for (i = 0; i < mapping->numRulesFromLDAP; i++) { + if (mapping->ruleFromLDAP[i]) /* See Comment below */ + free_mapping_rule(mapping->ruleFromLDAP[i]); + } + mapping->numRulesFromLDAP = 0; + + if (mapping->ruleFromLDAP != NULL) + free(mapping->ruleFromLDAP); + mapping->ruleFromLDAP = NULL; + + for (i = 0; i < mapping->numRulesToLDAP; i++) { + if (mapping->ruleToLDAP[i]) + /* + * Normally mapping->ruleToLDAP[i] should + * always be non-null if + * mapping->numRulesToLDAP is > 0. + * However it is possible to have data + * corruption where numRulesToLDAP gets + * some integer value even though no real + * data is present in mapping->ruleToLDAP. + */ + free_mapping_rule(mapping->ruleToLDAP[i]); + } + mapping->numRulesToLDAP = 0; + + if (mapping->ruleToLDAP != NULL) + free(mapping->ruleToLDAP); + mapping->ruleToLDAP = NULL; + + if (mapping->e != NULL) { + /* Similar logic as in above comment applies. */ + for (i = 0; i <= mapping->numSplits; i++) { + free_mapping_element(&mapping->e[i]); + } + free(mapping->e); + } + mapping->e = NULL; + + mapping->numSplits = 0; + + free(mapping); +} + +/* + * FUNCTION: free_config_info + * + * Frees __nis_config_info_t + * + * INPUT: __nis_config_info_t + */ + +void +free_config_info(__nis_config_info_t *config_info) +{ + if (config_info->config_dn != NULL) + free(config_info->config_dn); + config_info->config_dn = NULL; + + if (config_info->default_servers != NULL) + free(config_info->default_servers); + config_info->default_servers = NULL; + + if (config_info->proxy_dn != NULL) + free(config_info->proxy_dn); + config_info->proxy_dn = NULL; + + if (config_info->proxy_passwd != NULL) + free(config_info->proxy_passwd); + config_info->proxy_passwd = NULL; + + if (config_info->tls_cert_db != NULL) + free(config_info->tls_cert_db); + config_info->tls_cert_db = NULL; +} + +/* + * FUNCTION: free_proxy_info + * + * Frees __nis_ldap_proxy_info + * + * INPUT: __nis_ldap_proxy_info + */ + +void +free_proxy_info(__nis_ldap_proxy_info *proxy_info) +{ + if (proxy_info->tls_cert_db != NULL) + free(proxy_info->tls_cert_db); + proxy_info->tls_cert_db = NULL; + + if (proxy_info->default_servers != NULL) + free(proxy_info->default_servers); + proxy_info->default_servers = NULL; + + if (proxy_info->default_search_base != NULL) + free(proxy_info->default_search_base); + proxy_info->default_search_base = NULL; + + if (proxy_info->proxy_dn != NULL) + free(proxy_info->proxy_dn); + proxy_info->proxy_dn = NULL; + + if (proxy_info->proxy_passwd != NULL) + free(proxy_info->proxy_passwd); + proxy_info->proxy_passwd = NULL; + + if (proxy_info->default_nis_domain != NULL) + free(proxy_info->default_nis_domain); + proxy_info->default_nis_domain = NULL; +} + +/* + * FUNCTION: free_object_dn + * + * Frees __nis_object_dn_t + * + * INPUT: __nis_object_dn_t + */ + +void +free_object_dn(__nis_object_dn_t *obj_dn) +{ + __nis_object_dn_t *t; + int i; + + while (obj_dn != NULL) { + if (obj_dn->read.base != NULL) + free(obj_dn->read.base); + obj_dn->read.base = NULL; + if (obj_dn->read.attrs != NULL) + free(obj_dn->read.attrs); + obj_dn->read.attrs = NULL; + if (obj_dn->write.base != NULL) + free(obj_dn->write.base); + obj_dn->write.base = NULL; + if (obj_dn->write.attrs != NULL) + free(obj_dn->write.attrs); + obj_dn->write.attrs = NULL; + if (obj_dn->dbIdName != NULL) + free(obj_dn->dbIdName); + obj_dn->dbIdName = NULL; + for (i = 0; i < obj_dn->numDbIds; i++) + free_mapping_rule(obj_dn->dbId[i]); + obj_dn->numDbIds = 0; + + if (obj_dn->dbId != NULL) + free(obj_dn->dbId); + obj_dn->dbId = NULL; + + t = obj_dn; + obj_dn = obj_dn->next; + free(t); + } +} + +/* + * FUNCTION: free_index + * + * Frees __nis_index_t + * + * INPUT: __nis_index_t + */ + +void +free_index(__nis_index_t *index) +{ + int i; + for (i = 0; i < index->numIndexes; i++) { + free(index->name[i]); + free_mapping_format(index->value[i]); + } + index->numIndexes = 0; + if (index->name != NULL) + free(index->name); + index->name = NULL; + if (index->value != NULL) + free(index->value); + index->value = NULL; +} + +/* + * FUNCTION: free_mapping_item + * + * Frees __nis_mapping_item_t + * + * INPUT: __nis_mapping_item_t + */ + +void +free_mapping_item(__nis_mapping_item_t *item) +{ + if (item == NULL) + return; + + if (item->name != NULL) + free(item->name); + item->name = NULL; + if (item->type == mit_nisplus) { + free_index(&item->searchSpec.obj.index); + if (item->searchSpec.obj.name != NULL) + free(item->searchSpec.obj.name); + item->searchSpec.obj.name = NULL; + } else if (item->type == mit_ldap) { + if (item->searchSpec.triple.base != NULL) + free(item->searchSpec.triple.base); + item->searchSpec.triple.base = NULL; + if (item->searchSpec.triple.attrs != NULL) + free(item->searchSpec.triple.attrs); + item->searchSpec.triple.attrs = NULL; + if (item->searchSpec.triple.element != NULL) { + free_mapping_element( + item->searchSpec.triple.element); + free(item->searchSpec.triple.element); + } + item->searchSpec.triple.element = NULL; + } + if (item->exItem != NULL) { + free_mapping_item(item->exItem); + free(item->exItem); + item->exItem = 0; + } +} + +/* + * FUNCTION: free_mapping_format + * + * Frees __nis_mapping_format_t + * + * INPUT: __nis_mapping_format_t + */ + +void +free_mapping_format(__nis_mapping_format_t *fmt) +{ + __nis_mapping_format_t *f = fmt; + + while (fmt->type != mmt_end) { + switch (fmt->type) { + case mmt_item: + break; + case mmt_string: + if (fmt->match.string != NULL) + free(fmt->match.string); + fmt->match.string = NULL; + break; + case mmt_single: + if (fmt->match.single.lo != NULL) + free(fmt->match.single.lo); + fmt->match.single.lo = NULL; + if (fmt->match.single.hi != NULL) + free(fmt->match.single.hi); + fmt->match.single.hi = NULL; + break; + case mmt_limit: + break; + case mmt_any: + break; + case mmt_berstring: + case mmt_berstring_null: + if (fmt->match.berString != NULL) + free(fmt->match.berString); + fmt->match.berString = NULL; + break; + case mmt_begin: + break; + case mmt_end: + break; + } + fmt++; + } + free(f); +} + +/* + * FUNCTION: free_mapping_sub_element + * + * Frees __nis_mapping_sub_element_t + * + * INPUT: __nis_mapping_sub_element_t + */ + +void +free_mapping_sub_element(__nis_mapping_sub_element_t *sub) +{ + int i; + + switch (sub->type) { + case me_item: + free_mapping_item(&sub->element.item); + break; + case me_print: + if (sub->element.print.fmt != NULL) + free_mapping_format(sub->element.print.fmt); + sub->element.print.fmt = NULL; + for (i = 0; i < sub->element.print.numItems; i++) + free_mapping_item(&sub->element.print.item[i]); + sub->element.print.numItems = 0; + if (sub->element.print.item != NULL) + free(sub->element.print.item); + sub->element.print.item = NULL; + break; + case me_split: + free_mapping_item(&sub->element.split.item); + break; + case me_extract: + if (sub->element.extract.fmt != NULL) + free_mapping_format(sub->element.extract.fmt); + sub->element.extract.fmt = NULL; + free_mapping_item(&sub->element.extract.item); + break; + } +} + +/* + * FUNCTION: read_line + * + * Gets next line in buffer - using '\' at end of line + * to indicate continuation. Lines beginning with # are + * ignored. start_line_num and start_line_num are + * maintained to track the line number currently being + * parsed. + * + * RETURN VALUE: The number of characters read. 0 for + * eof, -1 for error + * + * INPUT: file descriptor, buffer, and buffer size + */ + +int +read_line(int fd, char *buffer, int buflen) +{ + int linelen; + int rc; + char c; + bool_t skip_line = FALSE; + bool_t begin_line = TRUE; + static bool_t prev_cr = FALSE; + + start_line_num = cur_line_num; + (void) memset(buffer, 0, buflen); + for (; p_error == no_parse_error; ) { + linelen = 0; + while (linelen < buflen) { + rc = read(fd, &c, 1); + if (1 == rc) { + if (c == '\n' || c == '\r') { + if (c == '\n') { + if (prev_cr) { + prev_cr = FALSE; + continue; + } else { + if (linelen == 0) + start_line_num = + cur_line_num; + else { + if ( + is_string_ok( + buffer, + linelen)) { + (void) memset( + buffer, 0, + linelen); + linelen = 0; + cur_line_num++; + begin_line = + TRUE; + continue; + } + } + cur_line_num++; + } + prev_cr = FALSE; + } else { + prev_cr = TRUE; + if (linelen == 0) + start_line_num = + cur_line_num; + cur_line_num++; + } + if (skip_line) { + skip_line = FALSE; + if (linelen == 0) + start_line_num = + cur_line_num; + } else if (linelen > 0 && + buffer[linelen - 1] + == ESCAPE_CHAR) { + --linelen; + } else if (linelen > 0) { + buffer[linelen] = '\0'; + return (linelen); + } + begin_line = TRUE; + } else { + if (begin_line) + skip_line = c == POUND_SIGN; + begin_line = FALSE; + if (!skip_line) + buffer[linelen++] = c; + } + } else { + if (linelen > 0 && + buffer[linelen - 1] == ESCAPE_CHAR) { + /* continuation on last line */ + p_error = parse_bad_continuation_error; + return (-1); + } else { + buffer[linelen] = '\0'; + return (linelen); + } + } + } + p_error = parse_line_too_long; + } + return (-1); +} + +/* + * FUNCTION: finish_parse + * + * Adds any elements not configured, fully qualifies + * names + * + * RETURN VALUE: 0 on success, -1 on failure + */ + +int +finish_parse( + __nis_ldap_proxy_info *proxy_info, + __nis_table_mapping_t **table_mapping) +{ + __nis_table_mapping_t *t; + __nis_table_mapping_t *t1; + __nis_table_mapping_t *t2; + __nis_table_mapping_t *t_del = NULL; + int i; + int j; + int k; + __nis_object_dn_t *objectDN; + __nis_mapping_rlhs_t *lhs; + __nis_mapping_element_t *e; + char *s; + int errnum; + + /* set to default those values yet set */ + if (proxy_info->auth_method == + (auth_method_t)NO_VALUE_SET) { + p_error = parse_no_proxy_auth_error; + report_error(NULL, NULL); + return (-1); + } + + if (proxy_info->default_servers == NULL) { + p_error = parse_no_ldap_server_error; + report_error(NULL, NULL); + return (-1); + } + + if (proxy_info->tls_method == (tls_method_t)NO_VALUE_SET) + proxy_info->tls_method = no_tls; + else if (proxy_info->tls_method == ssl_tls && + (proxy_info->tls_cert_db == NULL || + *proxy_info->tls_cert_db == '\0')) { + p_error = parse_no_cert_db; + report_error(NULL, NULL); + return (-1); + } + + if (proxy_info->default_nis_domain == NULL) + proxy_info->default_nis_domain = + s_strdup(__nis_rpc_domain()); + else if (*proxy_info->default_nis_domain == '\0') { + free(proxy_info->default_nis_domain); + proxy_info->default_nis_domain = + s_strdup(__nis_rpc_domain()); + } + if (proxy_info->default_nis_domain != NULL) + append_dot(&proxy_info->default_nis_domain); + + if (proxy_info->tls_method == ssl_tls) { + if ((errnum = ldapssl_client_init( + proxy_info->tls_cert_db, NULL)) < 0) { + p_error = parse_ldapssl_client_init_error; + report_error(ldapssl_err2string(errnum), NULL); + return (-1); + } + } + + if (proxy_info->default_search_base == NULL) + proxy_info->default_search_base = + get_default_ldap_base(proxy_info->default_nis_domain); + + /* convert a relative dn to a fullly qualified dn */ + (void) make_full_dn(&proxy_info->proxy_dn, + proxy_info->default_search_base); + + if (p_error != no_parse_error) { + report_error(NULL, NULL); + return (-1); + } + + /* + * Create a list of potential delete mappings + * those have NULL objectDNs, but badly also rules + * that are missing object dn's will be included. + * We will use the ttl field to determine if the + * delete rule is actually used + */ + t2 = NULL; + for (t = *table_mapping; t != NULL; t = t1) { + t1 = t->next; + if (t->objectDN == NULL) { + if (t2 == NULL) + *table_mapping = t1; + else + t2->next = t1; + t->next = t_del; + t_del = t; + t->ttl = 0; + } else + t2 = t; + } + + for (t = *table_mapping; t != NULL; t = t->next) { + objectDN = t->objectDN; + while (objectDN != NULL) { + if (objectDN->dbIdName != NULL) { + s = objectDN->dbIdName; + t1 = find_table_mapping(s, strlen(s), t_del); + if (t1 == NULL) { + p_error = parse_no_db_del_mapping_rule; + report_error2(objectDN->dbIdName, t->dbId); + return (-1); + } else if (t1->objName != NULL || + t1->numRulesToLDAP == 0 || + t1->numRulesFromLDAP != 0) { + p_error = parse_invalid_db_del_mapping_rule; + report_error(t1->dbId, NULL); + return (-1); + } + objectDN->dbId = + dup_mapping_rules(t1->ruleToLDAP, + t1->numRulesToLDAP); + if (objectDN->dbId == NULL) { + break; + } + objectDN->numDbIds = t1->numRulesToLDAP; + t1->ttl++; + } + objectDN = objectDN->next; + } + } + + for (t = t_del; t != NULL; t = t1) { + t1 = t->next; + if (t->ttl == 0) { + p_error = parse_no_object_dn; + report_error(t->dbId, NULL); + } + free_table_mapping(t); + } + + if (p_error != no_parse_error) + return (-1); + + /* set to default those table mapping values yet set */ + for (t = *table_mapping; t != NULL; t = t->next) { + if (t->objName == 0) { + p_error = parse_no_object_dn; + report_error(t->dbId, NULL); + return (-1); + } + if (!yp2ldap) { + if (!add_domain(&t->objName, + proxy_info->default_nis_domain)) { + report_error(NULL, NULL); + return (-1); + } + } + if (t->initTtlHi == (time_t)NO_VALUE_SET) + t->initTtlHi = DEFAULT_TTL_HIGH; + if (t->initTtlLo == (time_t)NO_VALUE_SET) + t->initTtlLo = DEFAULT_TTL_LOW; + if (t->ttl == (time_t)NO_VALUE_SET) + t->ttl = DEFAULT_TTL; + objectDN = t->objectDN; + + /* fixup relative dn's */ + while (objectDN != NULL) { + if (!yp2ldap) { + if (!make_full_dn(&objectDN->read.base, + proxy_info->default_search_base)) + break; + } + if (objectDN->write.scope != LDAP_SCOPE_UNKNOWN) { + if (objectDN->write.base != NULL && + !make_full_dn(&objectDN->write.base, + proxy_info->default_search_base)) + break; + if (objectDN->write.base == NULL) { + objectDN->write.base = + s_strdup(objectDN->read.base); + if (objectDN->write.base == NULL) + break; + } + } + objectDN = objectDN->next; + } + + if (p_error != no_parse_error) { + report_error(NULL, NULL); + return (-1); + } + + /* Check for ruleToLDAP with no rhs */ + for (i = 0; i < t->numRulesToLDAP; i++) { + if (t->ruleToLDAP[i]->rhs.numElements == 0) { + p_error = parse_unexpected_data_end_rule; + report_error(t->dbId, NULL); + return (-1); + } + } + + /* populate cols field */ + if (!yp2ldap) { + for (i = 0; i < t->numRulesFromLDAP; i++) { + lhs = &t->ruleFromLDAP[i]->lhs; + for (j = 0; j < lhs->numElements; j++) { + e = &lhs->element[j]; + switch (e->type) { + case me_item: + if (!add_column(t, + e->element.item.name)) { + report_error( + NULL, NULL); + return (-1); + } + break; + case me_match: + for (k = 0; + k < e->element.match.numItems; + k++) + if (!add_column(t, + e->element.match.item[k].name)) { + report_error( + NULL, NULL); + return (-1); + } + break; + } + } + } + } + } + return (0); +} + +/* + * FUNCTION: set_default_values + * + * Sets unconfigured values to their default value + */ + +void +set_default_values(__nis_ldap_proxy_info *proxy_info, + __nis_config_t *config_info, __nisdb_table_mapping_t *table_info) +{ + if (proxy_info->bind_timeout.tv_sec == (time_t)NO_VALUE_SET) + proxy_info->bind_timeout.tv_sec = DEFAULT_BIND_TIMEOUT; + if (proxy_info->search_timeout.tv_sec == (time_t)NO_VALUE_SET) + proxy_info->search_timeout.tv_sec = + (yp2ldap)?DEFAULT_YP_SEARCH_TIMEOUT: + DEFAULT_SEARCH_TIMEOUT; + if (proxy_info->modify_timeout.tv_sec == (time_t)NO_VALUE_SET) + proxy_info->modify_timeout.tv_sec = DEFAULT_MODIFY_TIMEOUT; + if (proxy_info->add_timeout.tv_sec == (time_t)NO_VALUE_SET) + proxy_info->add_timeout.tv_sec = DEFAULT_ADD_TIMEOUT; + if (proxy_info->delete_timeout.tv_sec == (time_t)NO_VALUE_SET) + proxy_info->delete_timeout.tv_sec = DEFAULT_DELETE_TIMEOUT; + + if (proxy_info->search_time_limit == (int)NO_VALUE_SET) + proxy_info->search_time_limit = DEFAULT_SEARCH_TIME_LIMIT; + if (proxy_info->search_size_limit == (int)NO_VALUE_SET) + proxy_info->search_size_limit = DEFAULT_SEARCH_SIZE_LIMIT; + + if (proxy_info->follow_referral == (follow_referral_t)NO_VALUE_SET) + proxy_info->follow_referral = no_follow; + + switch (config_info->initialUpdate) { + case (__nis_initial_update_t)NO_VALUE_SET: + case (__nis_initial_update_t)INITIAL_UPDATE_NO_ACTION: + case (__nis_initial_update_t)NO_INITIAL_UPDATE_NO_ACTION: + config_info->initialUpdate = ini_none; + break; + case (__nis_initial_update_t)FROM_NO_INITIAL_UPDATE: + config_info->initialUpdate = from_ldap; + break; + case (__nis_initial_update_t)TO_NO_INITIAL_UPDATE: + config_info->initialUpdate = to_ldap; + break; + } + if (config_info->threadCreationError == + (__nis_thread_creation_error_t)NO_VALUE_SET) + config_info->threadCreationError = pass_error; + if (config_info->threadCreationErrorTimeout.attempts == NO_VALUE_SET) + config_info->threadCreationErrorTimeout.attempts = + DEFAULT_THREAD_ERROR_ATTEMPTS; + if (config_info->threadCreationErrorTimeout.timeout == + (time_t)NO_VALUE_SET) + config_info->threadCreationErrorTimeout.timeout = + DEFAULT_THREAD_ERROR_TIME_OUT; + if (config_info->dumpError == + (__nis_dump_error_t)NO_VALUE_SET) + config_info->dumpError = de_retry; + if (config_info->dumpErrorTimeout.attempts == NO_VALUE_SET) + config_info->dumpErrorTimeout.attempts = + DEFAULT_DUMP_ERROR_ATTEMPTS; + if (config_info->dumpErrorTimeout.timeout == (time_t)NO_VALUE_SET) + config_info->dumpErrorTimeout.timeout = + DEFAULT_DUMP_ERROR_TIME_OUT; + if (config_info->resyncService == + (__nis_resync_service_t)NO_VALUE_SET) + config_info->resyncService = from_copy; + if (config_info->updateBatching == + (__nis_update_batching_t)NO_VALUE_SET) + config_info->updateBatching = accumulate; + if (config_info->updateBatchingTimeout.timeout == (time_t)NO_VALUE_SET) + config_info->updateBatchingTimeout.timeout = + DEFAULT_BATCHING_TIME_OUT; + if (config_info->numberOfServiceThreads == (int)NO_VALUE_SET) + config_info->numberOfServiceThreads = + DEFAULT_NUMBER_OF_THREADS; + if (config_info->emulate_yp == (int)NO_VALUE_SET) + config_info->emulate_yp = + DEFAULT_YP_EMULATION; + if (config_info->maxRPCRecordSize == (int)NO_VALUE_SET) + config_info->maxRPCRecordSize = RPC_MAXDATASIZE; + + if (table_info->retrieveError == + (__nis_retrieve_error_t)NO_VALUE_SET) + table_info->retrieveError = use_cached; + if (table_info->retrieveErrorRetry.attempts == NO_VALUE_SET) + table_info->retrieveErrorRetry.attempts = + DEFAULT_RETRIEVE_ERROR_ATTEMPTS; + if (table_info->retrieveErrorRetry.timeout == (time_t)NO_VALUE_SET) + table_info->retrieveErrorRetry.timeout = + DEFAULT_RETRIEVE_ERROR_TIME_OUT; + if (table_info->storeError == + (__nis_store_error_t)NO_VALUE_SET) + table_info->storeError = sto_retry; + if (table_info->storeErrorRetry.attempts == NO_VALUE_SET) + table_info->storeErrorRetry.attempts = + DEFAULT_STORE_ERROR_ATTEMPTS; + if (table_info->storeErrorRetry.timeout == (time_t)NO_VALUE_SET) + table_info->storeErrorRetry.timeout = + DEFAULT_STORE_ERROR_TIME_OUT; + if (table_info->refreshError == + (__nis_refresh_error_t)NO_VALUE_SET) + table_info->refreshError = continue_using; + if (table_info->refreshErrorRetry.attempts == NO_VALUE_SET) + table_info->refreshErrorRetry.attempts = + DEFAULT_REFRESH_ERROR_ATTEMPTS; + if (table_info->refreshErrorRetry.timeout == (time_t)NO_VALUE_SET) + table_info->refreshErrorRetry.timeout = + DEFAULT_REFRESH_ERROR_TIME_OUT; + if (table_info->matchFetch == + (__nis_match_fetch_t)NO_VALUE_SET) + table_info->matchFetch = no_match_only; +} + +__nis_table_mapping_t * +find_table_mapping(const char *s, int len, __nis_table_mapping_t *table_mapping) +{ + __nis_table_mapping_t *t; + + for (t = table_mapping; t != NULL; t = t->next) + if (strlen(t->dbId) == len && + strncasecmp(t->dbId, s, len) == 0) + break; + return (t); +} + +void +append_dot(char **str) +{ + char *s = *str; + int len = strlen(s); + + if (len == 0 || s[len - 1] != PERIOD_CHAR) { + s = s_realloc(s, len + 2); + if (s != NULL) { + s[len] = PERIOD_CHAR; + s[len+1] = '\0'; + *str = s; + } + } +} + +void +append_comma(char **str) +{ + + char *s = *str; + int len = strlen(s); + + if (len == 0 || s[len - 1] != COMMA_CHAR) { + s = s_realloc(s, len + 2); + if (s != NULL) { + s[len] = COMMA_CHAR; + s[len+1] = '\0'; + *str = s; + } + } +} + +/* + * FUNCTION: make_full_dn + * + * Appends the base dn if a relative ldap dn + * (invoked only for LDAP write cycle) + * + * RETURN VALUE: FALSE if error + * TRUE if __nis_index_t returned + * + * INPUT: the relative dn and ldap base + */ + +bool_t +make_full_dn(char **dn, const char *base) +{ + int len; + int len1; + + if (*dn == NULL) { + *dn = s_strdup(base); + } else { + len = strlen(*dn); + if (len > 0 && (*dn)[len-1] == COMMA_CHAR) { + len1 = strlen(base) + 1; + *dn = s_realloc(*dn, len + len1); + if (*dn != NULL) + (void) strcpy(*dn + len, base); + } + } + return (*dn != NULL); +} + +/* + * FUNCTION: make_fqdn + * + * Appends the base dn if a relative ldap dn + * (invoked only for LDAP read cycle) + * + * RETURN VALUE: FALSE if error + * TRUE if success + * + * INPUT: the relative dn and ldap base + */ +bool_t +make_fqdn(__nis_object_dn_t *dn, const char *base) +{ + int len; + int len1; + + if (dn == NULL) { + return (FALSE); + } else { + while (dn != NULL && dn->read.base != NULL) { + len = strlen(dn->read.base); + if (len > 0 && (dn->read.base)[len-1] == COMMA_CHAR) { + len1 = strlen(base) + 1; + dn->read.base = + s_realloc(dn->read.base, len + len1); + if (dn->read.base != NULL) + (void) strlcpy(dn->read.base + len, + base, len1); + else + return (FALSE); + } + dn = dn->next; + } + } + return (TRUE); +} + +/* + * FUNCTION: get_default_ldap_base + * + * Gets the default LDAP search base from the + * nis+ default domain + * + * RETURN VALUE: NULL if error + * the default base + * + * INPUT: the nis domain + */ + +char * +get_default_ldap_base(const char *domain) +{ + + int len = strlen(domain); + int i; + int count = len + 4; + char *base; + + for (i = 0; i < len - 1; i++) + if (domain[i] == PERIOD_CHAR) + count += 4; + if ((base = malloc(count)) == NULL) { + p_error = parse_no_mem_error; + } else { + (void) strcpy(base, "dc="); + count = 3; + for (i = 0; i < len - 1; i++) { + if (domain[i] == PERIOD_CHAR) { + (void) strcpy(base + count, ",dc="); + count += 4; + } else { + base[count++] = domain[i]; + } + } + base[count] = '\0'; + } + return (base); +} + +/* + * FUNCTION: add_domain + * + * Appends the base domain if a relative object name + * + * RETURN VALUE: FALSE if error + * TRUE if OK + * + * INPUT: the relative object name and base domain + * name + */ + +bool_t +add_domain(char **objName, const char *domain) +{ + int len; + int len1; + bool_t trailing_dot; + char *obj_name; + + if (domain == NULL || *objName == NULL) { + p_error = parse_internal_error; + return (FALSE); + } + len1 = strlen(domain); + trailing_dot = (len1 > 0 && domain[len1 - 1] == PERIOD_CHAR) ? + 0 : 1; + len = strlen(*objName); + if (len == 0 || (*objName)[len - 1] != PERIOD_CHAR) { + obj_name = s_realloc(*objName, + len + len1 + 2 + trailing_dot); + if (obj_name != NULL) { + obj_name[len++] = PERIOD_CHAR; + (void) strcpy(obj_name + len, domain); + if (trailing_dot != 0) { + obj_name[len + len1] = PERIOD_CHAR; + obj_name[len + len1 + 1] = '\0'; + } + *objName = obj_name; + } + } + + return (*objName != NULL); +} + +bool_t +dup_index(__nis_index_t *in, __nis_index_t *out) +{ + int i; + int j; + + out->name = (char **)s_calloc(in->numIndexes, sizeof (char *)); + if (out->name == NULL) + return (FALSE); + out->value = (__nis_mapping_format_t **) + s_calloc(in->numIndexes, sizeof (__nis_mapping_format_t *)); + if (out->value == NULL) { + free(out->name); + out->name = NULL; + return (FALSE); + } + + for (i = 0; i < in->numIndexes; i++) { + out->name[i] = s_strdup(in->name[i]); + if (out->name[i] == NULL) + break; + out->value[i] = dup_format_mapping(in->value[i]); + if (out->value[i] == NULL) + break; + } + if (i < in->numIndexes) { + for (j = 0; j <= i; j++) { + if (out->name[j] != NULL) + free(out->name[j]); + if (out->value[j] != NULL) + free_mapping_format(out->value[j]); + } + free(out->name); + out->name = NULL; + free(out->value); + out->value = NULL; + } else { + out->numIndexes = in->numIndexes; + } + return (i == in->numIndexes); +} + +bool_t +dup_mapping_item(__nis_mapping_item_t *in, __nis_mapping_item_t *out) +{ + bool_t ret; + + if (in->type == mit_nisplus) { + ret = dup_index(&in->searchSpec.obj.index, + &out->searchSpec.obj.index); + if (!ret) + return (ret); + if (in->searchSpec.obj.name != NULL) { + out->searchSpec.obj.name = + s_strdup(in->searchSpec.obj.name); + if (out->searchSpec.obj.name == NULL) + return (FALSE); + } else + out->searchSpec.obj.name = NULL; + } else if (in->type == mit_ldap) { + if (in->searchSpec.triple.base != NULL) { + out->searchSpec.triple.base = + s_strdup(in->searchSpec.triple.base); + if (out->searchSpec.triple.base == NULL) + return (FALSE); + } else + out->searchSpec.triple.base = NULL; + out->searchSpec.triple.scope = + in->searchSpec.triple.scope; + if (in->searchSpec.triple.attrs != NULL) { + out->searchSpec.triple.attrs = + s_strdup(in->searchSpec.triple.attrs); + if (out->searchSpec.triple.attrs == NULL) + return (FALSE); + } else + out->searchSpec.triple.attrs = NULL; + if (in->searchSpec.triple.element != NULL) { + out->searchSpec.triple.element = + (__nis_mapping_element_t *) + s_calloc(1, sizeof (__nis_mapping_element_t)); + if (out->searchSpec.triple.element != NULL) + dup_mapping_element( + in->searchSpec.triple.element, + out->searchSpec.triple.element); + if (out->searchSpec.triple.element == NULL) + return (FALSE); + } else + out->searchSpec.triple.element = NULL; + } + + if (in->name != NULL) { + out->name = s_strdup(in->name); + if (out->name == NULL) + return (FALSE); + } else + out->name = NULL; + out->type = in->type; + out->repeat = in->repeat; + if (in->exItem) { + out->exItem = (__nis_mapping_item_t *)s_malloc + (sizeof (__nis_mapping_item_t)); + if (out->exItem == NULL) + return (FALSE); + else { + (void) memset + (out->exItem, 0, sizeof (out->exItem[0])); + if (!dup_mapping_item + (in->exItem, out->exItem)) + p_error = parse_internal_error; + } + } else + out->exItem = NULL; + + return (p_error == no_parse_error); +} + +__nis_mapping_format_t * +dup_format_mapping(__nis_mapping_format_t *in) +{ + int i; + __nis_mapping_format_t *out; + bool_t got_end; + + i = 0; + while (in[i].type != mmt_end) + i++; + out = (__nis_mapping_format_t *)s_calloc( + i + 1, sizeof (__nis_mapping_format_t)); + if (out != NULL) { + got_end = FALSE; + for (i = 0; !got_end; i++) { + switch (in[i].type) { + case mmt_item: + break; + case mmt_string: + out[i].match.string = + s_strdup(in[i].match.string); + break; + case mmt_single: + out[i].match.single.numRange = + in[i].match.single.numRange; + out[i].match.single.lo = + s_malloc(in[i].match.single.numRange); + if (out[i].match.single.lo == NULL) + break; + out[i].match.single.hi = + s_malloc(in[i].match.single.numRange); + if (out[i].match.single.hi == NULL) + break; + memcpy(out[i].match.single.lo, + in[i].match.single.lo, + in[i].match.single.numRange); + memcpy(out[i].match.single.hi, + in[i].match.single.hi, + in[i].match.single.numRange); + break; + case mmt_limit: + out[i].match.limit = in[i].match.limit; + break; + case mmt_any: + break; + case mmt_berstring: + out[i].match.berString = + s_strdup(in[i].match.berString); + break; + case mmt_begin: + break; + case mmt_end: + got_end = TRUE; + break; + default: + p_error = parse_internal_error; + } + if (p_error != no_parse_error) + break; + out[i].type = in[i].type; + } + if (p_error != no_parse_error) { + free_mapping_format(out); + out = NULL; + } + } + + return (out); +} + +bool_t +dup_mapping_sub_element( + __nis_mapping_sub_element_t *in, + __nis_mapping_sub_element_t *out) +{ + bool_t ret = FALSE; + int i; + + switch (in->type) { + case me_item: + ret = dup_mapping_item(&in->element.item, + &out->element.item); + break; + case me_print: + out->element.print.fmt = + dup_format_mapping(in->element.print.fmt); + if (out->element.print.fmt == NULL) + break; + out->element.print.numItems = + in->element.print.numItems; + out->element.print.item = (__nis_mapping_item_t *) + s_calloc(in->element.print.numItems, + sizeof (__nis_mapping_item_t)); + if (out->element.print.item == NULL) + break; + for (i = 0; i < in->element.print.numItems; i++) + if (!dup_mapping_item( + &in->element.print.item[i], + &out->element.print.item[i])) + break; + if (i < in->element.print.numItems) + break; + ret = TRUE; + out->element.print.doElide = in->element.print.doElide; + out->element.print.elide = in->element.print.elide; + break; + case me_split: + ret = dup_mapping_item(&in->element.split.item, + &out->element.split.item); + out->element.split.delim = in->element.split.delim; + break; + case me_extract: + out->element.extract.fmt = + dup_format_mapping(in->element.extract.fmt); + if (out->element.extract.fmt == NULL) + break; + ret = dup_mapping_item(&in->element.extract.item, + &out->element.extract.item); + break; + default: + p_error = parse_internal_error; + } + out->type = in->type; + + return (ret); +} + +bool_t +dup_mapping_element( + __nis_mapping_element_t *in, + __nis_mapping_element_t *out) +{ + bool_t ret = FALSE; + int i; + + if (in == NULL) + return (ret); + + switch (in->type) { + case me_item: + ret = dup_mapping_item(&in->element.item, + &out->element.item); + break; + case me_print: + out->element.print.fmt = + dup_format_mapping(in->element.print.fmt); + if (out->element.print.fmt == NULL) + break; + out->element.print.numSubElements = + in->element.print.numSubElements; + out->element.print.subElement = + (__nis_mapping_sub_element_t *) + s_calloc(in->element.print.numSubElements, + sizeof (__nis_mapping_sub_element_t)); + if (out->element.print.subElement == NULL) + break; + for (i = 0; i < in->element.print.numSubElements; i++) + if (!dup_mapping_sub_element( + &in->element.print.subElement[i], + &out->element.print.subElement[i])) + break; + if (i < in->element.print.numSubElements) + break; + ret = TRUE; + out->element.print.doElide = in->element.print.doElide; + out->element.print.elide = in->element.print.elide; + break; + case me_split: + ret = dup_mapping_item(&in->element.split.item, + &out->element.split.item); + out->element.split.delim = in->element.split.delim; + break; + case me_match: + out->element.match.fmt = + dup_format_mapping(in->element.match.fmt); + if (out->element.match.fmt == NULL) + break; + out->element.match.numItems = + in->element.match.numItems; + out->element.match.item = (__nis_mapping_item_t *) + s_calloc(in->element.match.numItems, + sizeof (__nis_mapping_item_t)); + if (out->element.match.item == NULL) + break; + for (i = 0; i < in->element.match.numItems; i++) + if (!dup_mapping_item( + &in->element.match.item[i], + &out->element.match.item[i])) + break; + if (i < in->element.match.numItems) + break; + ret = TRUE; + break; + case me_extract: + out->element.extract.fmt = + dup_format_mapping(in->element.extract.fmt); + if (out->element.extract.fmt == NULL) + break; + ret = dup_mapping_item(&in->element.extract.item, + &out->element.extract.item); + break; + default: + p_error = parse_internal_error; + } + out->type = in->type; + + return (ret); +} + +__nis_mapping_rule_t * +dup_mapping_rule(__nis_mapping_rule_t *in) +{ + int i; + __nis_mapping_rlhs_t *r_in; + __nis_mapping_rlhs_t *r_out; + __nis_mapping_rule_t *out; + + out = (__nis_mapping_rule_t *) + s_calloc(1, sizeof (__nis_mapping_rule_t)); + if (out != NULL) { + r_in = &in->lhs; + r_out = &out->lhs; + r_out->numElements = r_in->numElements; + r_out->element = (__nis_mapping_element_t *)s_calloc + (r_in->numElements, sizeof (__nis_mapping_element_t)); + if (r_out->element == NULL) { + free_mapping_rule(out); + return (NULL); + } + for (i = 0; i < r_in->numElements; i++) { + if (!dup_mapping_element(&r_in->element[i], + &r_out->element[i])) + break; + } + if (i < r_in->numElements) { + free_mapping_rule(out); + return (NULL); + } + + r_in = &in->rhs; + r_out = &out->rhs; + r_out->numElements = r_in->numElements; + r_out->element = (__nis_mapping_element_t *)s_calloc + (r_in->numElements, sizeof (__nis_mapping_element_t)); + if (r_out->element == NULL) { + free_mapping_rule(out); + return (NULL); + } + for (i = 0; i < r_in->numElements; i++) { + if (!dup_mapping_element(&r_in->element[i], + &r_out->element[i])) + break; + } + if (i < r_in->numElements) { + free_mapping_rule(out); + return (NULL); + } + } + return (out); +} + +__nis_mapping_rule_t ** +dup_mapping_rules(__nis_mapping_rule_t **rules, int n_rules) +{ + int i, j; + __nis_mapping_rule_t **r; + + r = (__nis_mapping_rule_t **)s_calloc(n_rules, + sizeof (__nis_mapping_rule_t *)); + if (r != NULL) { + for (i = 0; i < n_rules; i++) { + r[i] = dup_mapping_rule(rules[i]); + if (r[i] == NULL) { + for (j = 0; j < i; j++) + free_mapping_rule(r[j]); + free(r); + r = NULL; + break; + } + } + } + return (r); +} + +/* + * FUNCTION: add_column + * + * Adds a column name to the column list in __nis_table_mapping_t + * + * RETURN VALUE: FALSE if error + * TRUE if __nis_index_t returned + * + * INPUT: the __nis_table_mapping_t and column name + */ + +bool_t +add_column(__nis_table_mapping_t *t, const char *col_name) +{ + int i; + char **cols = NULL; + + if (!yp2ldap) { + for (i = 0; i < t->numColumns; i++) { + if (strcasecmp(col_name, t->column[i]) == 0) + return (TRUE); + } + } + cols = (char **)s_realloc(t->column, (t->numColumns + 1) * + sizeof (char *)); + if (cols == NULL) + return (FALSE); + t->column = cols; + cols[t->numColumns] = s_strdup(col_name); + if (cols[t->numColumns] == NULL) + return (FALSE); + t->numColumns++; + return (TRUE); +} + +/* + * FUNCTION: add_element + * + * Adds a __nis_mapping_element_t to __nis_mapping_rlhs_t + * + * RETURN VALUE: FALSE if error + * TRUE if __nis_index_t returned + * + * INPUT: the __nis_mapping_element_t and + * __nis_mapping_rlhs_t + */ + +bool_t +add_element( + __nis_mapping_element_t *e, + __nis_mapping_rlhs_t *m) +{ + __nis_mapping_element_t *e1; + int i; + int n = m->numElements; + + e1 = (__nis_mapping_element_t *)s_realloc(m->element, + (n + 1) * sizeof (__nis_mapping_element_t)); + if (e1 == NULL) { + e1 = m->element; + for (i = 0; i < n; i++) + free_mapping_element(e1++); + if (m->element != NULL) + free(m->element); + m->element = NULL; + m->numElements = 0; + } else { + e1[m->numElements++] = *e; + free(e); + m->element = (__nis_mapping_element_t *)e1; + } + return (e1 != NULL); +} + +/* + * FUNCTION: get_next_object_dn_token + * + * Get the next token in parsing object_dn + * + * RETURN VALUE: NULL if error + * position of beginning next token after + * token + * + * INPUT: the attribute value + */ + +const char * +get_next_object_dn_token( + const char **begin_ret, + const char **end_ret, + object_dn_token *token) +{ + object_dn_token t = dn_no_token; + const char *s = *begin_ret; + const char *begin; + const char *end = *end_ret; + const char *s1; + bool_t in_quotes; + + while (s < end && is_whitespace(*s)) + s++; + if (s >= end) { + /* EMPTY */ + } else if (*s == SEMI_COLON_CHAR) { + t = dn_semi_token; + s++; + } else if (*s == QUESTION_MARK) { + t = dn_ques_token; + s++; + } else if (*s == COLON_CHAR) { + t = dn_colon_token; + s++; + } else if (*s == OPEN_PAREN_CHAR) { + begin = s; + s = get_ldap_filter(&begin, &end); + if (s != NULL) { + t = dn_text_token; + *begin_ret = begin; + *end_ret = end; + } + } else { + begin = s; + in_quotes = FALSE; + while (s < end) { + if (*s == ESCAPE_CHAR) { + if (s + 2 > end) { + p_error = parse_unmatched_escape; + s = NULL; + break; + } + s++; + } else if (*s == DOUBLE_QUOTE_CHAR) { + in_quotes = ! in_quotes; + } else if (in_quotes) + ; + else if (*s == SEMI_COLON_CHAR || + *s == QUESTION_MARK || + *s == COLON_CHAR) + break; + s++; + } + if (s != NULL) { + s1 = s - 1; + while (is_whitespace(*s1)) + s1--; + s1++; + if (same_string("base", begin, s1 - begin)) + t = dn_base_token; + else if (same_string("one", begin, s1 - begin)) + t = dn_one_token; + else if (same_string("sub", begin, s1 - begin)) + t = dn_sub_token; + else + t = dn_text_token; + *begin_ret = begin; + *end_ret = s1; + } + } + *token = t; + return (s); +} + +/* + * FUNCTION: get_next_token + * + * Get the next token in parsing mapping attribute + * + * RETURN VALUE: NULL if error + * position of beginning next token after + * token + * + * INPUT: the attribute value + */ + +const char * +get_next_token(const char **begin_token, const char **end_token, token_type *t) +{ + const char *s = *begin_token; + const char *end_s = *end_token; + const char *s_begin; + + while (s < end_s && is_whitespace(*s)) + s++; + if (s == end_s) { + *t = no_token; + return (s); + } + + s_begin = s; + + if (*s == OPEN_PAREN_CHAR) { + *begin_token = s; + s++; + *end_token = s; + while (s < end_s && is_whitespace(*s)) + s++; + *t = open_paren_token; + } else if (*s == DOUBLE_QUOTE_CHAR) { + s++; + while (s < end_s) { + if (*s == ESCAPE_CHAR) + s += 2; + else if (*s == DOUBLE_QUOTE_CHAR) + break; + else + s++; + } + if (s >= end_s) { + p_error = parse_unmatched_escape; + return (NULL); + } + + *t = quoted_string_token; + *begin_token = s_begin + 1; + *end_token = s++; + } else if (*s == EQUAL_CHAR || *s == COMMA_CHAR || + *s == CLOSE_PAREN_CHAR || *s == COLON_CHAR) { + if (*s == EQUAL_CHAR) + *t = equal_token; + else if (*s == COMMA_CHAR) + *t = comma_token; + else if (*s == CLOSE_PAREN_CHAR) + *t = close_paren_token; + else + *t = colon_token; + *begin_token = s; + *end_token = ++s; + } else { + s_begin = s; + while (s < end_s && !is_whitespace(*s)) { + if (*s == ESCAPE_CHAR) + s += 2; + else if (*s == EQUAL_CHAR || *s == CLOSE_PAREN_CHAR || + *s == OPEN_PAREN_CHAR || *s == COMMA_CHAR || + *s == COLON_CHAR || *s == OPEN_BRACKET || + *s == CLOSE_BRACKET) + break; + else + s++; + } + if (s > end_s) { + p_error = parse_unmatched_escape; + return (NULL); + } + *t = string_token; + *end_token = s; + *begin_token = s_begin; + } + if (s) { + while (s < end_s && is_whitespace(*s)) + s++; + } + return (s); +} + +/* + * FUNCTION: skip_token + * + * Skip over the specified token - An error is set if + * next token does not match expected token + * + * RETURN VALUE: NULL if error + * position of beginning next token after + * token + * + * INPUT: the attribute value + */ + +const char * +skip_token(const char *s, const char *end_s, token_type t) +{ + bool_t match; + char c = 0; + + if (s == NULL) + return (s); + while (s < end_s && is_whitespace(*s)) + s++; + c = (s == end_s) ? 0 : *s; + switch (t) { + case equal_token: + match = c == EQUAL_CHAR; + if (!match) + p_error = parse_equal_expected_error; + break; + case comma_token: + match = c == COMMA_CHAR; + if (!match) + p_error = parse_comma_expected_error; + break; + case close_paren_token: + match = c == CLOSE_PAREN_CHAR; + if (!match) + p_error = parse_close_paren_expected_error; + break; + default: + match = FALSE; + break; + } + if (match) { + s++; + while (s < end_s && is_whitespace(*s)) + s++; + } else { + s = NULL; + } + return (s); +} + +/* + * FUNCTION: get_next_extract_format_item + * + * Get the next format token from the string. Note that + * get_next_extract_format_item may change the input string. + * + * RETURN VALUE: NULL if error + * position of beginning next token after + * token + * + * INPUT: the format string + */ + +const char * +get_next_extract_format_item( + const char *begin_fmt, + const char *end_fmt, + __nis_mapping_format_t *fmt) +{ + const char *s = begin_fmt; + const char *s_end = end_fmt; + bool_t escape; + bool_t in_range; + bool_t got_char; + bool_t done; + int numRange; + char *lo = NULL; + char *hi = NULL; + bool_t skip_ber; + + for (; p_error == no_parse_error; ) { + if (s >= s_end) + break; + + if (*s == PERCENT_SIGN) { + s++; + /* + * If the format is %s, it is interpreted + * as a string. + */ + if (s >= s_end) { + p_error = parse_unsupported_format; + break; + } + skip_ber = FALSE; + switch (*s) { + case 's': + fmt->type = mmt_item; + break; + case 'n': /* null */ + case 'x': /* skip the next element */ + skip_ber = TRUE; + /* FALLTHRU */ + case 'b': /* boolean */ + case 'e': /* enumerated */ + case 'i': /* int */ + case 'o': /* octet string */ + case 'B': /* bit string */ + fmt->match.berString = s_strndup(s, 1); + fmt->type = skip_ber ? + mmt_berstring_null : + mmt_berstring; + break; + case 'a': /* octet string */ + if (yp2ldap) { + fmt->match.berString = + s_strndup(s, 1); + fmt->type = skip_ber ? + mmt_berstring_null : + mmt_berstring; + break; + } /* else FALLTHRU */ + case '{': /* begin sequence */ + case '[': /* begin set */ + case '}': /* end sequence */ + case ']': /* end set */ + case 'l': /* length of next item */ + case 'O': /* octet string */ + case 't': /* tag of next item */ + case 'T': /* skip tag of next item */ + case 'v': /* seq of strings */ + case 'V': /* seq of strings + lengths */ + default: + p_error = parse_bad_ber_format; + break; + } + s++; + } else if (*s == ASTERIX_CHAR) { + fmt->type = mmt_any; + s++; + while (s < s_end && *s == ASTERIX_CHAR) + s++; + + } else if (*s == OPEN_BRACKET) { + escape = FALSE; + in_range = FALSE; + got_char = FALSE; + numRange = 0; + done = FALSE; + s++; + for (; s < s_end; s++) { + if (escape) { + escape = FALSE; + } else if (*s == DASH_CHAR) { + if (in_range || !got_char) { + p_error = parse_unexpected_dash; + break; + } + in_range = TRUE; + got_char = FALSE; + continue; + } else if (*s == CLOSE_BRACKET) { + if (in_range) { + p_error = parse_unexpected_dash; + } + done = TRUE; + break; + } else if (*s == ESCAPE_CHAR) { + escape = TRUE; + continue; + } + if (in_range) { + hi[numRange - 1] = *s; + in_range = FALSE; + } else { + lo = s_realloc(lo, numRange + 1); + hi = s_realloc(hi, numRange + 1); + if (lo == NULL || hi == NULL) + break; + lo[numRange] = *s; + hi[numRange] = *s; + numRange++; + got_char = TRUE; + } + } + if (p_error != no_parse_error) { + break; + } else if (!done) { + p_error = parse_mismatched_brackets; + break; + } + s++; + fmt->type = mmt_single; + fmt->match.single.numRange = numRange; + fmt->match.single.lo = (unsigned char *)lo; + fmt->match.single.hi = (unsigned char *)hi; + } else { + /* go to next key symbol - copy escaped key symbols */ + escape = FALSE; + done = FALSE; + while (s < s_end) { + if (escape) + escape = FALSE; + else { + switch (*s) { + case OPEN_BRACKET: + case ASTERIX_CHAR: + case PERCENT_SIGN: + done = TRUE; + break; + case ESCAPE_CHAR: + escape = !escape; + break; + default: + break; + } + } + if (done) + break; + s++; + } + if (escape) { + p_error = parse_unmatched_escape; + break; + } + fmt->type = mmt_string; + fmt->match.string = + s_strndup_esc(begin_fmt, s - begin_fmt); + if (fmt->match.string == NULL) + break; + } + + if (p_error == no_parse_error) + return (s); + } + if (lo != NULL) + free(lo); + if (hi != NULL) + free(hi); + return (NULL); +} + +/* + * FUNCTION: get_next_print_format_item + * + * Get the next format token from the string + * + * RETURN VALUE: NULL if error + * position of beginning next token after + * token + * + * INPUT: the format string + */ + +const char * +get_next_print_format_item( + const char *begin_fmt, + const char *end_fmt, + __nis_mapping_format_t *fmt) +{ + const char *s = begin_fmt; + const char *s_end = end_fmt; + bool_t skip_ber; + + for (; p_error == no_parse_error; ) { + if (s >= s_end) { + p_error = parse_internal_error; + break; + } + + if (*s == PERCENT_SIGN) { + s++; + if (s >= s_end) { + p_error = parse_unsupported_format; + break; + } + skip_ber = FALSE; + /* + * If the format is %s, it is interpretted + * as a string. + */ + switch (*s) { + case 's': + fmt->type = mmt_item; + break; + case 'n': /* null */ + case 'x': /* skip the next element */ + skip_ber = TRUE; + /* FALLTHRU */ + case 'b': /* boolean */ + case 'e': /* enumerated */ + case 'i': /* int */ + case 'o': /* octet string */ + case 'B': /* bit string */ + fmt->match.berString = s_strndup(s, 1); + fmt->type = skip_ber ? + mmt_berstring_null : + mmt_berstring; + break; + case '{': /* begin sequence */ + case '[': /* begin set */ + case '}': /* end sequence */ + case ']': /* end set */ + case 'a': /* octet string */ + case 'l': /* length of next item */ + case 'O': /* octet string */ + case 't': /* tag of next item */ + case 'T': /* skip tag of next item */ + case 'v': /* seq of strings */ + case 'V': /* seq of strings + lengths */ + default: + p_error = parse_bad_ber_format; + break; + } + s++; + } else { + while (s < s_end) { + if (*s == PERCENT_SIGN) + break; + else if (*s == ESCAPE_CHAR) + s++; + s++; + } + if (s > s_end) { + p_error = parse_unmatched_escape; + break; + } + fmt->match.string = + s_strndup_esc(begin_fmt, s - begin_fmt); + if (fmt->match.string == NULL) + break; + fmt->type = mmt_string; + } + if (p_error == no_parse_error) + return (s); + } + return (NULL); +} + +/* + * FUNCTION: get_ldap_filter + * + * Gets an LDAP filter - see RFC 2254. Note that this does not + * determine if the ldap filter is valid. This only determines + * that the parentheses are balanced. + * + * RETURN VALUE: NULL if error + * position of beginning next token after + * filter + * + * INPUT: the begin and end of string + * + * OUTPUT: the begin and end of LDAP filter + * + */ + +const char * +get_ldap_filter(const char **begin, const char **end) +{ + const char *s = *begin; + const char *s_begin; + const char *s_end = *end; + int nParen; + + for (; p_error == no_parse_error; ) { + while (s < s_end && is_whitespace(*s)) + s++; + if (s == s_end) { + s = NULL; + break; + } + + s_begin = s; + if (*s == OPEN_PAREN_CHAR) { + nParen = 1; + s++; + while (s < s_end && nParen > 0) { + if (*s == ESCAPE_CHAR) + s++; + else if (*s == OPEN_PAREN_CHAR) + nParen++; + else if (*s == CLOSE_PAREN_CHAR) + nParen--; + s++; + } + if (nParen == 0) { + *begin = s_begin; + *end = s; + while (s < s_end && is_whitespace(*s)) + s++; + } else + s = NULL; + } else + s = NULL; + if (p_error == no_parse_error) + break; + } + if (s == NULL) + p_error = parse_invalid_ldap_search_filter; + + return (s); +} + +/* + * FUNCTION: get_ava_list + * + * Gets an attribute value assertion list + * + * RETURN VALUE: NULL if error + * position of beginning next token after + * after attribute assertion + * + * INPUT: the begin and end of string + * Indicator if ava list is part of a nisplus + * item + * + * OUTPUT: the begin and end of LDAP filter + * + */ + +const char * +get_ava_list(const char **begin, const char **end, bool_t end_nisplus) +{ + const char *s = *begin; + const char *s_begin; + const char *s_end = *end; + bool_t in_quote; + bool_t got_equal; + bool_t got_data; + + for (; p_error == no_parse_error; ) { + while (s < s_end && is_whitespace(*s)) + s++; + if (s == s_end) { + s = NULL; + break; + } + + in_quote = FALSE; + got_equal = FALSE; + got_data = FALSE; + s_begin = s; + while (s < s_end) { + if (*s == ESCAPE_CHAR) { + s++; + got_data = TRUE; + } else if (*s == DOUBLE_QUOTE_CHAR) { + in_quote = !in_quote; + got_data = TRUE; + } else if (in_quote) + ; + else if (*s == EQUAL_CHAR) { + if (end_nisplus && got_data && got_equal) + break; + if (!got_data || got_equal) { + got_equal = FALSE; + break; + } + got_equal = TRUE; + got_data = FALSE; + } else if (*s == COMMA_CHAR) { + if (!got_data || !got_equal) + break; + got_data = FALSE; + got_equal = FALSE; + } else if (is_whitespace(*s)) + ; + else + got_data = TRUE; + s++; + } + if (!got_data || !got_equal || in_quote) + s = NULL; + else { + *begin = s_begin; + *end = s; + while (s < s_end && is_whitespace(*s)) + s++; + } + if (p_error == no_parse_error) + break; + } + if (s == NULL) + p_error = parse_invalid_ldap_search_filter; + + return (s); +} + +/* Utility functions */ +bool_t +validate_dn(const char *s, int len) +{ + const char *end = s + len; + bool_t valid; + + valid = skip_get_dn(s, end) == end; + + if (!valid) + p_error = parse_bad_dn; + return (valid); +} + +bool_t +validate_ldap_filter(const char *s, const char *end) +{ + const char *s_begin; + const char *s_end; + + s_begin = s; + s_end = end; + + if (*s == OPEN_PAREN_CHAR) { + s = get_ldap_filter(&s_begin, &s_end); + } else { + /* Assume an attribute value list */ + s = get_ava_list(&s_begin, &s_end, FALSE); + } + if (s == NULL || s_end != end) + p_error = parse_invalid_ldap_search_filter; + + return (p_error == no_parse_error); +} + +char * +s_strndup(const char *s, int n) +{ + char *d = (char *)malloc(n + 1); + + if (d != NULL) { + (void) memcpy(d, s, n); + d[n] = '\0'; + } else { + p_error = parse_no_mem_error; + } + + return (d); +} + +char * +s_strndup_esc(const char *s, int n) +{ + char *d = (char *)malloc(n + 1); + int i; + int j; + + if (d != NULL) { + for (i = 0, j = 0; i < n; i++) { + if (s[i] == ESCAPE_CHAR) + i++; + d[j++] = s[i]; + } + d[j] = '\0'; + } else { + p_error = parse_no_mem_error; + } + + return (d); +} + +void * +s_calloc(size_t n, size_t size) +{ + void *d = (char *)calloc(n, size); + + if (d == NULL) { + p_error = parse_no_mem_error; + } + + return (d); +} + +void * +s_malloc(size_t size) +{ + void *d = malloc(size); + if (d == NULL) + p_error = parse_no_mem_error; + return (d); +} + +void * +s_realloc(void *s, size_t size) +{ + s = realloc(s, size); + if (s == NULL) + p_error = parse_no_mem_error; + return (s); +} + +char * +s_strdup(const char *s) +{ + return (s != NULL ? s_strndup(s, strlen(s)) : NULL); +} + +bool_t +is_whitespace(int c) +{ + return (c == ' ' || c == '\t'); +} + +bool_t +is_string_ok(char *buffer, int buflen) +{ + int i; + + if (buffer == NULL) + return (FALSE); + + for (i = 0; i < buflen; i++) { + if (!is_whitespace(buffer[i])) { + if (buffer[i] == POUND_SIGN) + return (TRUE); + else + return (FALSE); + } + } + return (TRUE); +} + +/* + * Returns true if the first string is contained at the beginning of the + * second string. Otherwise returns false. + */ + +bool_t +contains_string(const char *s1, const char *s2) +{ + return (strncasecmp(s1, s2, strlen(s1)) == 0); +} + +/* + * Returns the next character position in the second string, if the first + * string is contained at the beginning of the second string. Otherwise + * returns NULL. + */ + +const char * +skip_string(const char *s1, const char *s2, int len) +{ + int len1 = strlen(s1); + + if (len >= len1 && strncasecmp(s1, s2, strlen(s1)) == 0) + return (s2 + len1); + else + return (NULL); +} + +/* + * The second string is not necessarily null terminated. + * same_string returns true if the second string matches the first. + * Otherwise returns false. + */ + +bool_t +same_string(const char *s1, const char *s2, int len) +{ + int len1 = strlen(s1); + + return (len1 == len && strncasecmp(s1, s2, len1) == 0); +} + +void +report_error(const char *str, const char *attr) +{ + char fmt_buf[1024]; + int pos = 0; + + if (command_line_source != NULL) { + snprintf(fmt_buf, sizeof (fmt_buf), "Error parsing %s: ", + command_line_source); + pos = strlen(fmt_buf); + } else if (file_source != NULL) { + snprintf(fmt_buf, sizeof (fmt_buf), "Error parsing file '%s': ", + file_source); + pos = strlen(fmt_buf); + } else if (ldap_source != NULL) { + snprintf(fmt_buf, sizeof (fmt_buf), "Error for LDAP dn '%s': ", + ldap_source); + pos = strlen(fmt_buf); + } + + if (start_line_num != 0) { + snprintf(fmt_buf + pos, sizeof (fmt_buf) - pos, "at line %d: ", + start_line_num); + pos += strlen(fmt_buf + pos); + } + + if (attr != NULL) { + snprintf(fmt_buf + pos, sizeof (fmt_buf) - pos, + "for attribute %s: ", attr); + pos += strlen(fmt_buf + pos); + } + + if (cons != NULL) { + snprintf(fmt_buf + pos, sizeof (fmt_buf) - pos, "%s\n", + parse_error_msg[p_error]); + fprintf(cons, fmt_buf, str == NULL ? "" : str); + } else { + snprintf(fmt_buf + pos, sizeof (fmt_buf) - pos, "%s", + parse_error_msg[p_error]); + syslog(LOG_ERR, fmt_buf, str == NULL ? "" : str); + } +} + +void +report_error2( + const char *str1, + const char *str2) +{ + char fmt_buf[1024]; + + if (cons != NULL) { + snprintf(fmt_buf, sizeof (fmt_buf), + "%s\n", parse_error_msg[p_error]); + fprintf(cons, fmt_buf, str1, str2); + } else { + syslog(LOG_ERR, parse_error_msg[p_error], str1, str2); + } +} + +void +report_conn_error( + conn_error e, + const char *str1, + const char *str2) +{ + char fmt_buf[1024]; + + if (cons != NULL) { + snprintf(fmt_buf, sizeof (fmt_buf), + "%s\n", conn_error_msg[e]); + fprintf(cons, fmt_buf, + str1 == NULL ? "" : str1, + str2 == NULL ? "" : str2); + } else { + syslog(LOG_ERR, + conn_error_msg[e], + str1 == NULL ? "" : str1, + str2 == NULL ? "" : str2); + } +} + +void +report_info( + const char *str, + const char *arg) +{ + if (cons != NULL) { + fputs(str, cons); + if (arg != NULL) + fputs(arg, cons); + fputs("\n", cons); + } else + syslog(LOG_INFO, str, arg); +} |