/* * 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 2015 Gary Mills * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include /* 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); bool_t is_string_ok(char *, int); 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 != 0) mapping->commentChar = 0; 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; } /* FALLTHROUGH */ 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); }