/* * 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 2001-2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include "ldap_parse.h" #include "nis_parse_ldap_conf.h" #include "nis_parse_ldap_yp_util.h" #include "nis_parse_ldap_util.h" /* other attribute functions */ static char *getIndex(const char **s_cur, const char *end_s); static bool_t get_ttls(const char *s, const char *s_end, __nis_table_mapping_t *t_mapping); static __nis_object_dn_t *parse_object_dn(const char *s, const char *end); static int parse_name_fields(const char *name_s, const char *name_s_end, __nis_table_mapping_t *t_mapping); static void get_mapping_rule(const char *s, int len, __nis_table_mapping_t *tbl, bool_t to_ldap); static bool_t get_deleteDisp(const char *s_begin, const char *s_end, __nis_object_dn_t *obj_dn); /* mapping rule functions */ static const char *get_lhs(const char *s, const char *end_s, __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type); static const char *get_lhs_match(const char *s, const char *end_s, __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type); static const char *get_lhs_paren_item(const char *s, const char *end_s, __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type); static const char *get_rhs(const char *s, const char *end_s, __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type); static const char *get_mapping_item(const char *s, const char *end_s, __nis_mapping_item_t *item, __nis_mapping_item_type_t type); static const char *get_print_mapping_element(const char *s, const char *end_s, char *fmt_string, __nis_mapping_element_t *e, __nis_mapping_item_type_t item_type); static const char *get_subElement(const char *s, const char *end_s, __nis_mapping_sub_element_t *subelement, __nis_mapping_item_type_t type); static bool_t get_mapping_format(const char *fmt_string, __nis_mapping_format_t **fmt, int *nfmt, int *numItems, bool_t print_mapping); extern __yp_domain_context_t ypDomains; /* * FUNCTION: add_mapping_attribute * * Adds the attribute value to __nis_table_mapping_t * if the value is not yet set for the given database. * * RETURN VALUE: 0 on success, -1 on failure * * INPUT: attribute number and value */ int add_mapping_attribute( config_key attrib_num, const char *attrib_val, int attrib_len, __nis_table_mapping_t **table_mapping) { const char *s; const char *attrib_end; const char *db_id_end; const char *begin_token; char *index_string; __nis_object_dn_t *objectDN; __nis_table_mapping_t *t_mapping; __nis_table_mapping_t *t; bool_t new_mapping = FALSE; int nm; char *tmp_dbId; attrib_end = attrib_val + attrib_len; for (s = attrib_val; s < attrib_end; s++) if (*s == COLON_CHAR) break; if (s == attrib_end || *attrib_val == COLON_CHAR) { p_error = parse_unexpected_data_end_rule; return (-1); } db_id_end = s; while (s > attrib_val && is_whitespace(s[-1])) s--; if (s == attrib_val) { p_error = parse_unexpected_data_end_rule; return (-1); } if (yp2ldap) { tmp_dbId = s_strndup(attrib_val, s - attrib_val); if (tmp_dbId == NULL) { p_error = parse_no_mem_error; return (-1); } if (strchr(tmp_dbId, COMMA_CHAR)) { /* domain explicitly specified */ nm = check_domain_specific_order(tmp_dbId, attrib_num, *table_mapping, &ypDomains); /* * No logging is needed here, as * check_domain_specific_order * will log any appropriate errors. */ if (nm != 0) { free(tmp_dbId); return (-1); } } free(tmp_dbId); } if ((t_mapping = find_table_mapping(attrib_val, s - attrib_val, *table_mapping)) == NULL) { /* No mapping with this id, create one */ t_mapping = (__nis_table_mapping_t *) s_calloc(1, sizeof (__nis_table_mapping_t)); if (t_mapping == NULL) { p_error = parse_no_mem_error; return (-1); } (void) initialize_table_mapping(t_mapping); /* dbId is the label before the colon */ t_mapping->dbId = s_strndup(attrib_val, s - attrib_val); if (t_mapping->dbId == NULL) { p_error = parse_no_mem_error; free(t_mapping); return (-1); } new_mapping = TRUE; } else { /* a table mapping already exists, use it */ new_mapping = FALSE; } s = db_id_end + 1; while (s < attrib_end && is_whitespace(*s)) s++; switch (attrib_num) { case key_yp_map_flags: if (t_mapping->usedns_flag != 0 || t_mapping->securemap_flag != 0) { warn_duplicate_map(t_mapping->dbId, attrib_num); break; } while (is_whitespace(*s) && s < attrib_end) s++; while (s < attrib_end) { if (s < attrib_end && *s == 'b') t_mapping->usedns_flag = 1; if (s < attrib_end && *s == 's') t_mapping->securemap_flag = 1; s++; } break; case key_yp_comment_char: if (t_mapping->commentChar != DEFAULT_COMMENT_CHAR) { warn_duplicate_map(t_mapping->dbId, attrib_num); break; } while (is_whitespace(*s) && s < attrib_end) s++; if (s < attrib_end && (s+1) < attrib_end && (s+2) <= attrib_end) { while (is_whitespace(attrib_end[-1])) attrib_end--; while (*s != SINGLE_QUOTE_CHAR) s++; if (*s == SINGLE_QUOTE_CHAR && *(s+2) == SINGLE_QUOTE_CHAR) { t_mapping->commentChar = *(s+1); } else if (*s == SINGLE_QUOTE_CHAR && *(s+1) == SINGLE_QUOTE_CHAR) { t_mapping->commentChar = 0; } else { /* anything else is an error */ p_error = parse_bad_yp_comment_error; } break; } else { p_error = parse_bad_yp_comment_error; break; } case key_yp_repeated_field_separators: while (s < attrib_end && is_whitespace(*s)) s++; if (s < attrib_end) { while (is_whitespace(attrib_end[-1])) attrib_end--; while (s < attrib_end && *s != DOUBLE_QUOTE_CHAR) s++; s++; begin_token = s; while (s < attrib_end && *s != DOUBLE_QUOTE_CHAR) { if (*s == ESCAPE_CHAR) s++; s++; } t_mapping->separatorStr = s_strndup(begin_token, s - begin_token); if (t_mapping->separatorStr == NULL) break; } else { p_error = parse_bad_field_separator_error; } break; case key_yp_name_fields: case key_yp_split_field: if (t_mapping->e || t_mapping->numSplits > 0) { warn_duplicate_map(t_mapping->dbId, attrib_num); break; } if (parse_name_fields(s, attrib_end, t_mapping)) { p_error = parse_bad_name_field; } break; case key_yp_db_id_map: case key_db_id_map: if (t_mapping->objName != NULL) { warn_duplicate_map(t_mapping->dbId, attrib_num); break; } if (s < attrib_end && *s == OPEN_BRACKET) { index_string = getIndex(&s, attrib_end); if (index_string == NULL) break; (void) parse_index(index_string, index_string + strlen(index_string), &t_mapping->index); free(index_string); if (p_error != no_parse_error) break; } while (is_whitespace(*s) && s < attrib_end) s++; if (s < attrib_end) { while (is_whitespace(attrib_end[-1])) attrib_end--; t_mapping->objName = s_strndup_esc(s, attrib_end - s); } else { if (yp2ldap) { p_error = parse_bad_map_error; } else { t_mapping->objName = s_strndup(s, 0); } } break; case key_yp_entry_ttl: case key_entry_ttl: if (t_mapping->initTtlLo != (time_t)NO_VALUE_SET) { warn_duplicate_map(t_mapping->dbId, attrib_num); break; } if (!get_ttls(s, attrib_end, t_mapping)) p_error = parse_bad_ttl_format_error; break; case key_yp_ldap_object_dn: case key_ldap_object_dn: if (t_mapping->objectDN != NULL) { warn_duplicate_map(t_mapping->dbId, attrib_num); break; } objectDN = parse_object_dn(s, attrib_end); if (objectDN == NULL) break; t_mapping->objectDN = objectDN; t_mapping->seq_num = seq_num++; break; case key_nis_to_ldap_map: case key_nisplus_to_ldap_map: if (t_mapping->ruleToLDAP != 0) { warn_duplicate_map(t_mapping->dbId, attrib_num); break; } get_mapping_rule(s, attrib_end - s, t_mapping, TRUE); break; case key_ldap_to_nis_map: case key_ldap_to_nisplus_map: if (t_mapping->ruleFromLDAP != NULL) { warn_duplicate_map(t_mapping->dbId, attrib_num); break; } get_mapping_rule(s, attrib_end - s, t_mapping, FALSE); break; default: p_error = parse_internal_error; break; } if (p_error == no_parse_error) { if (new_mapping) { if (*table_mapping == NULL) *table_mapping = t_mapping; else { for (t = *table_mapping; t->next != NULL; t = t->next) ; t->next = t_mapping; } } } else { if (new_mapping) free_table_mapping(t_mapping); } return (p_error == no_parse_error ? 0 : -1); } /* * FUNCTION: add_ypdomains_attribute * * Adds the yp domains information to the __yp_domain_context_t * structure. * * RETURN: 0 on success, -1 on failure * * INPUT: attribute number and value */ int add_ypdomains_attribute( config_key attrib_num, const char *attrib_val, int attrib_len, __yp_domain_context_t *ypDomains) { const char *s; const char *attrib_end; int numDomains = 0; attrib_end = attrib_val + attrib_len; for (s = attrib_val; s < attrib_end; s++) { if (*s == COLON_CHAR) { break; } } while (s > attrib_val && is_whitespace(s[-1])) s--; if (s == attrib_val) { p_error = parse_unexpected_data_end_rule; return (-1); } if (ypDomains == NULL) { /* * No point allocating. We cant return the resulting structure, * so just return failure. Should not ever happen because we * are always called with a pointer to the global ypDomains * structure. */ return (-1); } switch (attrib_num) { case key_yp_domain_context: numDomains = ypDomains->numDomains; ypDomains->domainLabels = (char **)s_realloc(ypDomains->domainLabels, (numDomains + 1) * sizeof (ypDomains->domainLabels[0])); if (ypDomains->domainLabels == NULL) { p_error = parse_no_mem_error; free_yp_domain_context(ypDomains); break; } ypDomains->domainLabels[numDomains] = s_strndup(attrib_val, s - attrib_val); if (ypDomains->domainLabels[numDomains] == NULL) { p_error = parse_no_mem_error; free_yp_domain_context(ypDomains); break; } ypDomains->numDomains = numDomains + 1; while (s < attrib_end && is_whitespace(*s)) s++; if (*s == COLON_CHAR) s++; while (s < attrib_end && is_whitespace(*s)) s++; ypDomains->domains = (char **)s_realloc(ypDomains->domains, (numDomains + 1) * sizeof (ypDomains->domains[0])); if (ypDomains->domains == NULL) { p_error = parse_no_mem_error; free_yp_domain_context(ypDomains); break; } if (s < attrib_end) { while (is_whitespace(attrib_end[-1])) attrib_end--; ypDomains->domains[numDomains] = s_strndup_esc(s, attrib_end - s); if (ypDomains->domains[numDomains] == NULL) { p_error = parse_no_mem_error; free_yp_domain_context(ypDomains); break; } } else { p_error = parse_unexpected_yp_domain_end_error; free(ypDomains->domainLabels[numDomains]); ypDomains->domainLabels[numDomains] = NULL; ypDomains->numDomains--; free_yp_domain_context(ypDomains); } break; case key_yppasswdd_domains: ypDomains->yppasswddDomainLabels = (char **)s_realloc( ypDomains->yppasswddDomainLabels, (ypDomains->numYppasswdd + 1) * sizeof (ypDomains->yppasswddDomainLabels[0])); if (ypDomains->yppasswddDomainLabels == NULL) { p_error = parse_no_mem_error; break; } ypDomains->yppasswddDomainLabels [ypDomains->numYppasswdd] = s_strndup(attrib_val, s - attrib_val); if (ypDomains->yppasswddDomainLabels [ypDomains->numYppasswdd] == NULL) { p_error = parse_no_mem_error; } ypDomains->numYppasswdd++; break; } return (p_error == no_parse_error ? 0 : -1); } /* * FUNCTION: get_ttls * * Parse time to live attribute * * RETURN VALUE: TRUE on success, FALSE on failure * * INPUT: the attribute value */ static bool_t get_ttls( const char *s, const char *s_end, __nis_table_mapping_t *t_mapping) { time_t initTtlHi = 0; time_t initTtlLo = 0; time_t ttl = 0; time_t digit; /* * attribute should be of the form * initialTTLlo ":" initialTTLhi ":" runningTTL */ if (s == s_end) { p_error = parse_bad_ttl_format_error; return (FALSE); } if (isdigit(*s)) { while (s < s_end && isdigit(*s)) { digit = (*s++) - '0'; if (WILL_OVERFLOW_TIME(initTtlLo, digit)) initTtlLo = TIME_MAX; else initTtlLo = initTtlLo * 10 + digit; } } else { initTtlLo = ONE_HOUR; } while (s < s_end && is_whitespace(*s)) s++; if (s + 1 >= s_end || *s++ != COLON_CHAR) { p_error = parse_bad_ttl_format_error; return (FALSE); } while (s < s_end && is_whitespace(*s)) s++; if (isdigit(*s)) { while (s < s_end && isdigit(*s)) { digit = (*s++) - '0'; if (WILL_OVERFLOW_TIME(initTtlHi, digit)) initTtlHi = TIME_MAX; else initTtlHi = initTtlHi * 10 + digit; } } else { initTtlHi = initTtlLo; } while (s < s_end && is_whitespace(*s)) s++; if (s >= s_end || *s++ != COLON_CHAR) { p_error = parse_bad_ttl_format_error; return (FALSE); } while (s < s_end && is_whitespace(*s)) s++; if (isdigit(*s)) { while (s < s_end && isdigit(*s)) { digit = (*s++) - '0'; if (WILL_OVERFLOW_TIME(ttl, digit)) ttl = TIME_MAX; else ttl = ttl * 10 + digit; } } else { ttl = ONE_HOUR; } while (s < s_end && is_whitespace(*s)) s++; if (s != s_end) { p_error = parse_bad_ttl_format_error; return (FALSE); } t_mapping->initTtlLo = initTtlLo; t_mapping->initTtlHi = initTtlHi; t_mapping->ttl = ttl; return (TRUE); } /* * FUNCTION: parse_name_fields * * Parse yp name fields * * RETURN VALUE: 0 on success, non-zero on failure * * INPUTS: attrib_value and attribute_end pointers. */ static int parse_name_fields(const char *name_s, const char *name_s_end, __nis_table_mapping_t *t_map) { int i, n = 0; int nElements = 0; int numSplits = 0; int parse_next_line = 1; int itm_count = 0; const char *begin_fmt; const char *end_fmt; const char *begin_token; const char *end_token; char *fmt_string = NULL; __nis_mapping_format_t *base = NULL; __nis_mapping_item_t *item = NULL; __nis_mapping_element_t *elmnt = NULL; __nis_mapping_item_type_t item_type = mit_nisplus; token_type token; t_map->numColumns = 0; for (; parse_next_line > 0; parse_next_line--) { nElements = 0; item = NULL; base = NULL; while (name_s < name_s_end && *name_s != OPEN_PAREN_CHAR) name_s++; if (name_s == name_s_end) { p_error = parse_unexpected_data_end_rule; return (1); } while (name_s < name_s_end && *name_s != DOUBLE_QUOTE_CHAR) name_s++; if (name_s == name_s_end) { p_error = parse_unexpected_data_end_rule; return (1); } begin_fmt = ++name_s; /* start of format string */ while (name_s < name_s_end && *name_s != DOUBLE_QUOTE_CHAR) name_s++; if (name_s == name_s_end) { p_error = parse_unexpected_data_end_rule; return (1); } end_fmt = name_s; fmt_string = s_strndup(begin_fmt, end_fmt - begin_fmt); if (fmt_string == NULL) { p_error = parse_no_mem_error; return (2); } if (!get_mapping_format(fmt_string, &base, &n, NULL, FALSE)) { p_error = parse_internal_error; free(fmt_string); fmt_string = NULL; return (3); } free(fmt_string); fmt_string = NULL; for (n = 0; base[n].type != mmt_end; n++) { if (base[n].type != mmt_item && base[n].type != mmt_berstring) { if (base[n].type == mmt_berstring_null) base[n].type = mmt_berstring; continue; } while (name_s < name_s_end && *name_s != COMMA_CHAR) name_s++; name_s++; /* now at comma char */ while (name_s < name_s_end && is_whitespace(*name_s)) name_s++; begin_token = name_s++; end_token = name_s_end; name_s = get_next_token( &begin_token, &end_token, &token); if (name_s == NULL) { p_error = parse_item_expected_error; return (4); } if (token != string_token) { p_error = parse_item_expected_error; return (5); } item = (__nis_mapping_item_t *)s_realloc(item, (nElements + 1) * sizeof (__nis_mapping_item_t)); if (item == NULL) { p_error = parse_no_mem_error; return (2); } name_s = get_mapping_item(begin_token, name_s_end, &item[nElements], item_type); if (name_s == NULL) { p_error = parse_unmatched_escape; for (n = 0; n < (nElements + 1); n++) free_mapping_item(&item[n]); free_mapping_format(base); return (4); } nElements++; } if (p_error != no_parse_error) { for (n = 0; n < (nElements + 1); n++) free_mapping_item(&item[n]); free_mapping_format(base); return (6); } name_s = skip_token(name_s, name_s_end, close_paren_token); if (name_s == NULL) { p_error = parse_close_paren_expected_error; for (n = 0; n < (nElements + 1); n++) free_mapping_item(&item[n]); free_mapping_format(base); return (4); } while (name_s < name_s_end && is_whitespace(*name_s)) name_s++; if (*name_s == COMMA_CHAR) parse_next_line++; if (nElements == 0) { p_error = parse_no_match_item; for (n = 0; n < (nElements + 1); n++) free_mapping_item(&item[n]); free_mapping_format(base); return (7); } elmnt = (__nis_mapping_element_t *)s_realloc(elmnt, (numSplits + 1) * sizeof (__nis_mapping_element_t)); if (elmnt == NULL) { for (n = 0; n < (nElements + 1); n++) free_mapping_item(&item[n]); free_mapping_format(base); p_error = parse_no_mem_error; return (2); } elmnt[numSplits].type = me_match; elmnt[numSplits].element.match.numItems = nElements; elmnt[numSplits].element.match.item = item; elmnt[numSplits].element.match.fmt = base; item = NULL; base = NULL; t_map->e = elmnt; t_map->numSplits = numSplits; n = t_map->numColumns; for (i = n, itm_count = 0; i < n + nElements; i++) { if (t_map->e[numSplits].element. match.item[itm_count].name) { if (!add_column(t_map, t_map->e[numSplits].element. match.item[itm_count].name)) return (1); itm_count++; } else { p_error = parse_internal_error; for (n = 0; n < (nElements + 1); n++) free_mapping_item(&item[n]); free_mapping_format(base); free_mapping_element(elmnt); return (1); } } numSplits++; } elmnt = NULL; if (item != NULL) { for (n = 0; n < t_map->numColumns; n++) { free_mapping_item(&item[n]); } free(item); } if (elmnt != NULL) free_mapping_element(elmnt); if (base != NULL) free_mapping_format(base); return (p_error == no_parse_error ? 0 : -1); } /* * FUNCTION: parse_object_dn * * Parse object dn attribute * * RETURN VALUE: __nis_object_dn_t on success * NULL on failure * * INPUT: the attribute value */ static __nis_object_dn_t * parse_object_dn(const char *s, const char *end) { const char *s_begin; const char *s_end; object_dn_token token; parse_object_dn_state dn_state = dn_begin_parse; __nis_object_dn_t *obj_dn = NULL; __nis_object_dn_t *next = NULL; __nis_object_dn_t *last = NULL; /* * The attribute should be of form * objectDN *( ";" objectDN ) * objectDN = readObjectSpec [":"[writeObjectSpec]] * readObjectSpec = [baseAndScope [filterAttrValList]] * writeObjectSpec = [baseAndScope [attrValList [":" deleteDisp]]] */ while (s < end) { s_begin = s; s_end = end; s = get_next_object_dn_token(&s_begin, &s_end, &token); if (s == NULL) break; if (token == dn_no_token || token == dn_semi_token) { if (obj_dn == NULL) obj_dn = next; else last->next = next; last = next; next = NULL; if (token == dn_no_token) break; dn_state = dn_begin_parse; } if (next == NULL) { next = (__nis_object_dn_t *) s_calloc(1, sizeof (__nis_object_dn_t)); if (next == NULL) break; next->read.scope = LDAP_SCOPE_ONELEVEL; next->write.scope = LDAP_SCOPE_UNKNOWN; next->delDisp = dd_always; } if (token == dn_semi_token) continue; switch (dn_state) { case dn_begin_parse: if (token == dn_ques_token) dn_state = dn_got_read_q_scope; else if (token == dn_colon_token) { dn_state = dn_got_write_colon; next->write.scope = LDAP_SCOPE_ONELEVEL; } else { if (!validate_dn(s_begin, s_end - s_begin)) break; next->read.base = s_strndup_esc(s_begin, s_end - s_begin); dn_state = dn_got_read_dn; } break; case dn_got_read_dn: if (token == dn_ques_token) dn_state = dn_got_read_q_scope; else if (token == dn_colon_token) { dn_state = dn_got_write_colon; next->write.scope = LDAP_SCOPE_ONELEVEL; } else p_error = parse_object_dn_syntax_error; break; case dn_got_read_q_scope: if (token == dn_ques_token) dn_state = dn_got_read_q_filter; else if (token == dn_colon_token) { dn_state = dn_got_write_colon; next->write.scope = LDAP_SCOPE_ONELEVEL; } else if (token == dn_base_token) { next->read.scope = LDAP_SCOPE_BASE; dn_state = dn_got_read_scope; } else if (token == dn_one_token) { next->read.scope = LDAP_SCOPE_ONELEVEL; dn_state = dn_got_read_scope; } else if (token == dn_sub_token) { next->read.scope = LDAP_SCOPE_SUBTREE; dn_state = dn_got_read_scope; } else { p_error = parse_invalid_scope; } break; case dn_got_read_scope: if (token == dn_ques_token) dn_state = dn_got_read_q_filter; else if (token == dn_colon_token) { dn_state = dn_got_write_colon; next->write.scope = LDAP_SCOPE_ONELEVEL; } else p_error = parse_object_dn_syntax_error; break; case dn_got_read_q_filter: if (token == dn_ques_token) { p_error = parse_object_dn_syntax_error; } else if (token == dn_colon_token) { dn_state = dn_got_write_colon; next->write.scope = LDAP_SCOPE_ONELEVEL; } else { if (!validate_ldap_filter(s_begin, s_end)) break; next->read.attrs = s_strndup_esc(s_begin, s_end - s_begin); dn_state = dn_got_read_filter; } break; case dn_got_read_filter: if (token == dn_ques_token) { p_error = parse_object_dn_syntax_error; } else if (token == dn_colon_token) { dn_state = dn_got_write_colon; next->write.scope = LDAP_SCOPE_ONELEVEL; } else p_error = parse_object_dn_syntax_error; break; case dn_got_write_colon: if (token == dn_ques_token) dn_state = dn_got_write_q_scope; else if (token == dn_colon_token) { dn_state = dn_got_delete_colon; } else { if (!validate_dn(s_begin, s_end - s_begin)) break; next->write.base = s_strndup_esc(s_begin, s_end - s_begin); dn_state = dn_got_write_dn; } break; case dn_got_write_dn: if (token == dn_ques_token) dn_state = dn_got_write_q_scope; else if (token == dn_colon_token) { dn_state = dn_got_delete_colon; } else p_error = parse_object_dn_syntax_error; break; case dn_got_write_q_scope: if (token == dn_ques_token) dn_state = dn_got_write_q_filter; else if (token == dn_colon_token) { dn_state = dn_got_delete_colon; } else if (token == dn_base_token) { next->write.scope = LDAP_SCOPE_BASE; dn_state = dn_got_write_scope; } else if (token == dn_one_token) { next->write.scope = LDAP_SCOPE_ONELEVEL; dn_state = dn_got_write_scope; } else if (token == dn_sub_token) { next->write.scope = LDAP_SCOPE_SUBTREE; dn_state = dn_got_write_scope; } else { p_error = parse_invalid_scope; } break; case dn_got_write_scope: if (token == dn_ques_token) dn_state = dn_got_write_q_filter; else if (token == dn_colon_token) { dn_state = dn_got_delete_colon; } else p_error = parse_object_dn_syntax_error; break; case dn_got_write_q_filter: if (token == dn_ques_token) { p_error = parse_object_dn_syntax_error; } else if (token == dn_colon_token) { dn_state = dn_got_delete_colon; } else { if (!validate_ldap_filter(s_begin, s_end)) break; next->write.attrs = s_strndup_esc(s_begin, s_end - s_begin); dn_state = dn_got_write_filter; } break; case dn_got_write_filter: if (token == dn_ques_token) { p_error = parse_object_dn_syntax_error; } else if (token == dn_colon_token) { dn_state = dn_got_delete_colon; } else p_error = parse_semi_expected_error; break; case dn_got_delete_colon: if (token == dn_ques_token) { p_error = parse_object_dn_syntax_error; } else if (token == dn_colon_token) { p_error = parse_object_dn_syntax_error; } else { if (!get_deleteDisp(s_begin, s_end, next)) break; dn_state = dn_got_delete_dsp; } break; case dn_got_delete_dsp: p_error = parse_object_dn_syntax_error; break; } if (p_error != no_parse_error) break; } if (p_error != no_parse_error) { if (obj_dn != NULL) free_object_dn(obj_dn); if (next != NULL) free_object_dn(next); obj_dn = NULL; } else if (next != NULL) { if (obj_dn == NULL) obj_dn = next; else last->next = next; } else if (obj_dn == NULL) obj_dn = (__nis_object_dn_t *) s_calloc(1, sizeof (__nis_object_dn_t)); return (obj_dn); } /* * FUNCTION: get_mapping_rule * * Parse mapping rule attributes * * RETURN VALUE: None. Errors determined by p_error * * INPUT: the attribute value and mapping rule type */ static void get_mapping_rule( const char *s, int len, __nis_table_mapping_t *tbl, bool_t to_ldap) { const char *end_s = s + len; const char *begin_token; const char *end_token; __nis_mapping_rule_t **rule = NULL; __nis_mapping_rule_t *next = NULL; /* __nis_mapping_rule_t **r; */ token_type t; int nRules = 0; const char *s1; int i; /* * The attribute value is of the form * colattrspec *("," colattrspec) * colattrspec = lhs "=" rhs * lhs = lval | namespeclist * rhs = rval | [namespec] */ for (;;) { if ((next = (__nis_mapping_rule_t *) s_calloc(1, sizeof (__nis_mapping_rule_t))) == NULL) break; s = get_lhs(s, end_s, &next->lhs, to_ldap ? mit_ldap : mit_nisplus); if (s == NULL) break; begin_token = s; end_token = end_s; s1 = get_next_token(&begin_token, &end_token, &t); if (s1 == NULL) break; if (!(to_ldap && (t == comma_token || t == no_token))) { s = get_rhs(s, end_s, &next->rhs, to_ldap ? mit_nisplus : mit_ldap); if (s == NULL) break; } if (next->lhs.numElements > 1 && (next->rhs.numElements != 1 || next->rhs.element[0].type != me_split)) { p_error = parse_lhs_rhs_type_mismatch; break; } if (rule == NULL) { rule = (__nis_mapping_rule_t **) malloc(sizeof (__nis_mapping_rule_t *)); if (rule == NULL) break; } else { rule = (__nis_mapping_rule_t **)s_realloc(rule, (nRules + 1) * sizeof (__nis_mapping_rule_t *)); if (rule == NULL) break; } rule[nRules++] = next; next = NULL; begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; if (t == comma_token) continue; if (t != no_token) { p_error = parse_unexpected_data_end_rule; break; } if (to_ldap) { tbl->numRulesToLDAP = nRules; tbl->ruleToLDAP = rule; } else { tbl->numRulesFromLDAP = nRules; tbl->ruleFromLDAP = rule; } return; } if (rule) { for (i = 0; i < nRules; i++) free_mapping_rule(rule[i]); free(rule); } if (next) free_mapping_rule(next); } /* * FUNCTION: get_lhs * * Parse left hand side of mapping rule attribute * * RETURN VALUE: NULL if error * position of beginning rhs * * INPUT: the attribute value and mapping rule type */ static const char * get_lhs(const char *s, const char *end_s, __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type) { token_type t; const char *begin_token; const char *end_token; const char *sav_s; __nis_mapping_element_t *e = NULL; /* * lhs can be expressed as: * item * (item) * (item list) * (fmt, item list) * * lhs = lval | namespeclist * lval = "(" formatspec "," namespec *("," namespec) ")" * namespeclist = namespec | "(" namespec *("," namespec) ")" */ for (; p_error == no_parse_error; ) { begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; if (t == no_token) { p_error = parse_unexpected_data_end_rule; break; } e = (__nis_mapping_element_t *) s_calloc(1, sizeof (__nis_mapping_element_t)); if (e == NULL) break; if (t == open_paren_token) { free(e); e = NULL; begin_token = s; end_token = end_s; sav_s = s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; if (t == quoted_string_token) { s = get_lhs_match(sav_s, end_s, lhs, item_type); if (s == NULL) break; } else if (t == string_token) { s = get_lhs_paren_item(sav_s, end_s, lhs, item_type); if (s == NULL) break; } else { p_error = parse_bad_lhs_format_error; break; } } else if (t == string_token) { s = get_mapping_item(begin_token, end_s, &e->element.item, item_type); if (s == NULL) break; e->type = me_item; if (!add_element(e, lhs)) break; e = NULL; } else { p_error = parse_bad_lhs_format_error; break; } s = skip_token(s, end_s, equal_token); if (s == NULL) break; if (p_error == no_parse_error) return (s); } if (e != NULL) free_mapping_element(e); return (NULL); } /* * FUNCTION: get_lhs_match * * Parse left hand side of mapping rule attribute in case of * matching rule * * RETURN VALUE: NULL if error * position of beginning rhs * * INPUT: the attribute value and mapping rule type */ static const char * get_lhs_match( const char *s, const char *end_s, __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type) { token_type t; const char *begin_token; const char *end_token; int n = 0; int nElements = 0; char *fmt_string = NULL; __nis_mapping_format_t *base = NULL; __nis_mapping_item_t *item = NULL; __nis_mapping_item_t *itm; __nis_mapping_element_t *e; /* * lval = "(" formatspec "," namespec *("," namespec) ")" */ for (; p_error == no_parse_error; ) { begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL || t != quoted_string_token) { p_error = parse_internal_error; break; } fmt_string = s_strndup(begin_token, end_token - begin_token); if (fmt_string == NULL) break; if (!get_mapping_format(fmt_string, &base, &n, NULL, FALSE)) break; for (n = 0; base[n].type != mmt_end; n++) { if (base[n].type != mmt_item && base[n].type != mmt_berstring) { if (base[n].type == mmt_berstring_null) base[n].type = mmt_berstring; continue; } s = skip_token(s, end_s, comma_token); if (s == NULL) { p_error = parse_not_enough_extract_items; break; } begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; if (t != string_token) { p_error = parse_item_expected_error; break; } itm = (__nis_mapping_item_t *) s_realloc(item, (nElements + 1) * sizeof (__nis_mapping_item_t)); if (itm == NULL) break; item = itm; s = get_mapping_item(begin_token, end_s, &item[nElements], item_type); if (s == NULL) break; nElements++; } if (p_error != no_parse_error) break; s = skip_token(s, end_s, close_paren_token); if (s == NULL) break; free(fmt_string); fmt_string = NULL; if (nElements == 0) { p_error = parse_no_match_item; break; } e = (__nis_mapping_element_t *)s_calloc(1, sizeof (__nis_mapping_element_t)); if (e == NULL) break; e->type = me_match; e->element.match.numItems = nElements; e->element.match.item = item; e->element.match.fmt = base; lhs->numElements = 1; lhs->element = e; if (p_error == no_parse_error) return (s); } if (item == NULL) { for (n = 0; n < nElements; n++) free_mapping_item(&item[n]); free(item); } if (fmt_string != NULL) free(fmt_string); if (base != NULL) free_mapping_format(base); return (NULL); } /* * FUNCTION: get_lhs_paren_item * * Parse left hand side of mapping rule attribute in case of * (item1, ..., item-n) * * RETURN VALUE: NULL if error * position of beginning rhs * * INPUT: the attribute value and mapping rule type */ static const char * get_lhs_paren_item( const char *s, const char *end_s, __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type) { token_type t; const char *begin_token; const char *end_token; __nis_mapping_element_t *e = NULL; int n = 0; int i; /* * "(" namespec *("," namespec) ")" */ for (;;) { e = (__nis_mapping_element_t *)s_realloc(e, (n + 1) * sizeof (__nis_mapping_element_t)); if (e == NULL) break; s = get_mapping_item(s, end_s, &e[n].element.item, item_type); if (s == NULL) break; e[n].type = me_item; n++; begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s != NULL && t == close_paren_token) { lhs->numElements = n; if (n == 1) e[0].element.item.repeat = TRUE; lhs->element = e; return (s); } if (s == NULL || t != comma_token) { p_error = parse_comma_expected_error; break; } } for (i = 0; i < n; i++) free_mapping_element(&e[i]); if (e != NULL) free(e); return (NULL); } /* * FUNCTION: get_rhs * * Parse right hand side of mapping rule attribute * * RETURN VALUE: NULL if error * position of beginning next mapping rule * * INPUT: the attribute value and mapping rule type */ static const char * get_rhs( const char *s, const char *end_s, __nis_mapping_rlhs_t *rhs, __nis_mapping_item_type_t item_type) { /* * This handles the following cases: * name me_item * (name) me_item * (fmt, name-list) me_print * (item, fmt) me_extract */ token_type t; const char *begin_token; const char *end_token; char *str = NULL; __nis_mapping_format_t *fmt = NULL; __nis_mapping_element_t *e = NULL; __nis_mapping_item_t item; int n; (void) memset(&item, 0, sizeof (item)); for (; p_error == no_parse_error; ) { begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; e = (__nis_mapping_element_t *) s_calloc(1, sizeof (__nis_mapping_element_t)); if (e == NULL) break; if (t == string_token) { s = get_mapping_item(begin_token, end_s, &e->element.item, item_type); } else if (t == open_paren_token) { begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; if (t == string_token) { /* (item, fmt) - me_extract */ /* (item, "c") - me_split */ s = get_mapping_item(begin_token, end_s, &item, item_type); if (s == NULL) break; begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; else if (t == close_paren_token) { item.repeat = TRUE; e->element.item = item; e->type = me_item; rhs->numElements = 1; rhs->element = e; return (s); } else if (t != comma_token) { p_error = parse_comma_expected_error; break; } begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL || t != quoted_string_token) { p_error = parse_format_string_expected_error; break; } if (end_token == begin_token + 1 || (*begin_token == ESCAPE_CHAR && end_token == begin_token + 2)) { e->type = me_split; e->element.split.item = item; e->element.split.delim = *begin_token; } else { str = s_strndup(begin_token, end_token - begin_token); if (str == NULL) break; if (!get_mapping_format(str, &fmt, NULL, &n, FALSE)) break; free(str); str = NULL; if (n != 1) { p_error = parse_bad_extract_format_spec; break; } e->type = me_extract; e->element.extract.item = item; e->element.extract.fmt = fmt; } s = skip_token(s, end_s, close_paren_token); } else if (t == quoted_string_token) { /* (fmt, name-list) - me_print */ str = s_strndup(begin_token, end_token - begin_token); if (str == NULL) break; s = get_print_mapping_element(s, end_s, str, e, item_type); free(str); str = NULL; } else { p_error = parse_start_rhs_unrecognized; break; } } else { p_error = parse_start_rhs_unrecognized; break; } if (s == NULL) break; rhs->numElements = 1; rhs->element = e; if (p_error == no_parse_error) return (s); } if (str) free(str); if (fmt != NULL) free_mapping_format(fmt); if (e != NULL) free_mapping_element(e); free_mapping_item(&item); return (NULL); } /* * FUNCTION: get_print_mapping_element * * Parse a print mapping rule attribute in case of the form * (fmt, name-list) * * RETURN VALUE: NULL if error * position of beginning next mapping rule * * INPUT: the attribute value and mapping rule type */ static const char * get_print_mapping_element( const char *s, const char *end_s, char *fmt_string, __nis_mapping_element_t *e, __nis_mapping_item_type_t item_type) { token_type t; const char *begin_token; const char *end_token; char elide; bool_t doElide; __nis_mapping_format_t *base = NULL; __nis_mapping_sub_element_t *subElement = NULL; int n = 0; int nSub = 0; int numSubElements; for (; p_error == no_parse_error; ) { if (!get_mapping_format(fmt_string, &base, &n, &numSubElements, TRUE)) break; subElement = (__nis_mapping_sub_element_t *) s_calloc(numSubElements, sizeof (__nis_mapping_sub_element_t)); if (subElement == NULL) break; for (n = 0; base[n].type != mmt_end; n++) { if (base[n].type != mmt_item && base[n].type != mmt_berstring) { if (base[n].type == mmt_berstring_null) base[n].type = mmt_berstring; continue; } if (nSub < numSubElements) { s = skip_token(s, end_s, comma_token); if (s == NULL) { p_error = parse_bad_print_format; break; } } /* namelist may have parens around it */ s = get_subElement(s, end_s, &subElement[nSub], item_type); if (s == NULL) break; nSub++; } if (p_error != no_parse_error) break; begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL || t == no_token) { p_error = parse_unexpected_data_end_rule; break; } else if (t == close_paren_token) { doElide = FALSE; elide = '\0'; } else if (t == comma_token) { begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s != NULL && t == quoted_string_token && (end_token == begin_token + 1 || (*begin_token == ESCAPE_CHAR && end_token == begin_token + 2))) { if (numSubElements != 1 || subElement->type == me_extract || subElement->type == me_split) { p_error = parse_cannot_elide; break; } if (subElement->type == me_item && !subElement->element.item.repeat) { p_error = parse_cannot_elide; break; } elide = *begin_token; doElide = TRUE; } else { p_error = parse_bad_elide_char; break; } s = skip_token(s, end_s, close_paren_token); if (s == NULL) break; } e->type = me_print; e->element.print.fmt = base; e->element.print.numSubElements = numSubElements; e->element.print.subElement = subElement; e->element.print.elide = elide; e->element.print.doElide = doElide; if (p_error == no_parse_error) return (s); } if (base) free_mapping_format(base); if (subElement != NULL) { for (n = 0; n < numSubElements; n++) free_mapping_sub_element(&subElement[n]); free(subElement); } return (NULL); } /* * FUNCTION: get_mapping_item * * Parse attribute string to get mapping item * * RETURN VALUE: NULL if error * position of beginning next token after item * * INPUT: the attribute value and mapping rule type */ static const char * get_mapping_item( const char *s, const char *end_s, __nis_mapping_item_t *item, __nis_mapping_item_type_t type) { token_type t; const char *begin_token; const char *end_token; char *name = NULL; char *index_string; const char *s_sav; int len; (void) memset(item, 0, sizeof (*item)); /* * A namepec is defined as follows: * namespec = ["ldap:"] attrspec [searchTriple] | * ["nis+:"] colspec [objectspec] * * The form of the item is assumed to be as follows: * ["ldap:"] attrspec [searchTriple] * attrspec = attribute | "(" attribute ")" * searchTriple = ":" [baseDN] ["?" [scope] ["?" [filter]]] * baseDN = Base DN for search * scope = "base" | "one" | "sub" * filter = LDAP search filter * * The form of the objectspec is as follows: * ["nis+:"] colspec [objectspec] * objectspec = objectname | "[" indexlist "]" tablename * objectname = The name of a NIS+ object * tablename = The name of a NIS+ table * indexlist = colspec ["," colspec] * colspec = colname "=" colvalue * colname = The name of a column in the table * colvalue = colvaluestring | \" colvaluestring \" */ for (; p_error == no_parse_error; ) { while (s < end_s && is_whitespace(*s)) s++; len = end_s - s; if (yp2ldap) { if ((begin_token = skip_string("ldap:", s, len)) != NULL) { item->type = mit_ldap; } else if ((begin_token = skip_string("yp:", s, len)) != NULL) { item->type = mit_nisplus; } else { item->type = type; begin_token = s; } } else { if ((begin_token = skip_string("ldap:", s, len)) != NULL) { item->type = mit_ldap; } else if ((begin_token = skip_string("nis+:", s, len)) != NULL) { item->type = mit_nisplus; } else if ((begin_token = skip_string("nisplus:", s, len)) != NULL) { item->type = mit_nisplus; } else { item->type = type; begin_token = s; } } end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL || t != string_token) { p_error = parse_bad_item_format; break; } item->name = s_strndup_esc(begin_token, end_token - begin_token); if (item->name == NULL) break; if (item->type == mit_ldap) { item->searchSpec.triple.scope = LDAP_SCOPE_UNKNOWN; begin_token = s; end_token = end_s; s_sav = s; s = get_next_token(&begin_token, &end_token, &t); if (s != NULL && t == colon_token) { s = get_search_triple(s, end_s, &item->searchSpec.triple); if (s == NULL) break; } else s = s_sav; } else if (item->type == mit_nisplus) { while (s < end_s && is_whitespace(*s)) s++; if (s < end_s && *s == OPEN_BRACKET) { index_string = getIndex(&s, end_s); if (index_string == NULL) break; (void) parse_index(index_string, index_string + strlen(index_string), &item->searchSpec.obj.index); free(index_string); if (p_error != no_parse_error) break; } s_sav = s; begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s != NULL && t == string_token) { name = s_strndup_esc(begin_token, end_token - begin_token); if (name == NULL) break; item->searchSpec.obj.name = name; } else s = s_sav; } if (p_error == no_parse_error) return (s); } free_mapping_item(item); (void) memset(item, 0, sizeof (*item)); if (name == NULL) free(name); return (NULL); } static const char * get_print_sub_element(const char *s, const char *end_s, __nis_mapping_item_type_t type, __nis_mapping_sub_element_t *sub) { int k; int n; const char *begin_token; const char *end_token; token_type t; __nis_mapping_format_t *base; __nis_mapping_item_t *print_item; k = 0; base = sub->element.print.fmt; print_item = sub->element.print.item; sub->element.print.doElide = FALSE; sub->element.print.elide = '\0'; for (n = 0; base[n].type != mmt_end; n++) { if (base[n].type != mmt_item && base[n].type != mmt_berstring) { if (base[n].type == mmt_berstring_null) base[n].type = mmt_berstring; continue; } s = skip_token(s, end_s, comma_token); if (s == NULL) { p_error = parse_bad_print_format; break; } begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; /* * Determine if of the form * ("fmt", (item), "delim") or * ("fmt", item1, item2, ..., item n) */ if (t == open_paren_token) { if (sub->element.print.numItems != 1) { p_error = parse_invalid_print_arg; break; } s = get_mapping_item(s, end_s, &print_item[k++], type); s = skip_token(s, end_s, close_paren_token); s = skip_token(s, end_s, comma_token); if (s == NULL) { p_error = parse_bad_print_format; break; } begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; if (t != quoted_string_token || begin_token + 1 != end_token) { p_error = parse_bad_elide_char; break; } sub->element.print.elide = *begin_token; sub->element.print.doElide = TRUE; print_item[0].repeat = TRUE; break; } s = get_mapping_item(begin_token, end_s, &print_item[k++], type); if (s == NULL) break; if (p_error != no_parse_error) break; } return (p_error == no_parse_error ? s : NULL); } /* * FUNCTION: get_subElement * * Parse attribute string to get sub element item * * RETURN VALUE: NULL if error * position of beginning next token after item * * INPUT: the attribute value and mapping rule type */ static const char * get_subElement( const char *s, const char *end_s, __nis_mapping_sub_element_t *subelement, __nis_mapping_item_type_t type) { token_type t; const char *begin_token; const char *end_token; char *fmt_string; __nis_mapping_item_t item; __nis_mapping_element_type_t e_type; __nis_mapping_item_t *print_item = NULL; __nis_mapping_format_t *base = NULL; int n = 0; int numItems = 0; unsigned char delim; __nis_mapping_sub_element_t sub; /* * What is the form of we are expecting here * item me_item * (item) me_item * ("fmt", item1, item2, ..., item n) me_print * ("fmt", (item), "elide") me_print * (name, "delim") me_split * (item, "fmt") me_extract */ (void) memset(&item, 0, sizeof (item)); for (; p_error == no_parse_error; ) { begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; if (t == string_token) { /* me_item */ s = get_mapping_item(begin_token, end_s, &subelement->element.item, type); if (s == NULL) break; subelement->type = me_item; return (s); } else if (t != open_paren_token) { p_error = parse_item_expected_error; break; } begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; if (t != string_token && t != quoted_string_token) { p_error = parse_item_expected_error; break; } e_type = me_print; if (t == string_token) { /* me_item, me_extract or me_split */ s = get_mapping_item(begin_token, end_s, &item, type); if (s == NULL) break; begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) { p_error = parse_unexpected_data_end_rule; break; } else if (t == close_paren_token) { subelement->type = me_item; item.repeat = TRUE; subelement->element.item = item; if (yp2ldap) { while (s < end_s && is_whitespace(*s)) s++; if (s == end_s) { p_error = parse_unexpected_data_end_rule; break; } if (*s == DASH_CHAR && s < end_s) { s++; while (s < end_s && is_whitespace(*s)) s++; begin_token = s; end_token = end_s; subelement->element.item.exItem = (__nis_mapping_item_t *) s_malloc(sizeof (__nis_mapping_item_t)); if (!subelement-> element.item.exItem) break; s = get_mapping_item(s, end_s, subelement-> element.item.exItem, type); if (s == NULL) { p_error = parse_internal_error; free_mapping_item( subelement-> element.item.exItem); subelement-> element.item.exItem = NULL; break; } } } return (s); } else if (t != comma_token) { p_error = parse_comma_expected_error; break; } begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL || t != quoted_string_token) { p_error = parse_format_string_expected_error; break; } if (end_token == begin_token + 1 || (*begin_token == ESCAPE_CHAR && end_token == begin_token + 2)) { /* me_split */ delim = (unsigned char)end_token[-1]; s = skip_token(s, end_s, close_paren_token); if (s == NULL) break; subelement->element.split.item = item; subelement->element.split.delim = delim; subelement->type = me_split; return (s); } e_type = me_extract; } fmt_string = s_strndup(begin_token, end_token - begin_token); if (fmt_string == NULL) break; if (!get_mapping_format(fmt_string, &base, &n, &numItems, e_type == me_print)) { free(fmt_string); break; } free(fmt_string); if (numItems != 1 && e_type == me_extract) { p_error = numItems == 0 ? parse_not_enough_extract_items : parse_too_many_extract_items; break; } else if (numItems > 0 && e_type == me_print) { print_item = (__nis_mapping_item_t *)s_calloc(numItems, sizeof (__nis_mapping_item_t)); if (print_item == NULL) break; } if (e_type == me_print) { sub.element.print.numItems = numItems; sub.element.print.fmt = base; sub.element.print.item = print_item; s = get_print_sub_element(s, end_s, type, &sub); if (s == NULL) break; } s = skip_token(s, end_s, close_paren_token); if (s == NULL) break; subelement->type = e_type; if (e_type == me_extract) { subelement->element.extract.fmt = base; subelement->element.extract.item = item; } else { subelement->type = me_print; subelement->element.print.fmt = base; subelement->element.print.numItems = numItems; subelement->element.print.item = print_item; subelement->element.print.doElide = sub.element.print.doElide; subelement->element.print.elide = sub.element.print.elide; } if (p_error == no_parse_error) return (s); } free_mapping_item(&item); if (base != NULL) free_mapping_format(base); if (print_item) { for (n = 0; n < numItems; n++) free_mapping_item(&print_item[n]); free(print_item); } return (NULL); } /* * FUNCTION: skip_get_dn * * Get first token after dn * * RETURN VALUE: NULL if error (not valid dn) * position of beginning next token after dn * * INPUT: the attribute value */ const char * skip_get_dn(const char *dn, const char *end) { size_t len = 0; bool_t in_quote = FALSE; bool_t goteq = FALSE; bool_t gotch = FALSE; bool_t done = FALSE; bool_t last_comma = FALSE; const char *last_dn = dn; while (!done) { dn += len; if (last_comma) { last_dn = dn; last_comma = FALSE; } if (dn >= end) break; len = 1; switch (*dn) { case ESCAPE_CHAR: len = 2; gotch = TRUE; break; case DOUBLE_QUOTE_CHAR: in_quote = !in_quote; break; case QUESTION_MARK: case CLOSE_PAREN_CHAR: case COLON_CHAR: done = !in_quote; /* FALLTHRU */ case SEMI_COLON_CHAR: case PLUS_SIGN: case COMMA_CHAR: if (!in_quote) { if (!goteq || !gotch) return (last_dn); goteq = FALSE; gotch = FALSE; if (*dn != PLUS_SIGN) last_dn = dn; last_comma = *dn == COMMA_CHAR; } else { gotch = TRUE; } break; case EQUAL_CHAR: if (!in_quote) { if (!gotch || goteq) return (NULL); goteq = TRUE; gotch = FALSE; } else { gotch = TRUE; } break; default: if (!is_whitespace(*dn)) gotch = TRUE; break; } } if (dn == end) { if (!in_quote && goteq && gotch) last_dn = dn; } return (last_dn); } /* * FUNCTION: get_ldap_filter_element * * Get an ldap filter element for a given string * * RETURN VALUE: NULL if error * __nis_mapping_element_t if success * * INPUT: the string to parse */ static __nis_mapping_element_t * get_ldap_filter_element( const char *s, const char *end_s ) { token_type t; const char *begin_token; const char *end_token; char *format_str; __nis_mapping_element_t *e = NULL; begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL || t != open_paren_token) return (NULL); begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL || t != quoted_string_token) return (NULL); format_str = s_strndup(begin_token, end_token - begin_token); if (format_str == NULL) return (NULL); e = (__nis_mapping_element_t *) s_calloc(1, sizeof (__nis_mapping_element_t)); if (e != NULL) { (void) get_print_mapping_element(s, end_s, format_str, e, mit_nisplus); if (p_error != no_parse_error) { free_mapping_element(e); e = NULL; } } free(format_str); return (e); } /* * FUNCTION: get_search_triple * * Get the search triple or if NULL determine if valid * * RETURN VALUE: NULL if error * position of beginning next token after * search triple * * INPUT: the attribute value */ const char * get_search_triple( const char *s, const char *end_s, __nis_search_triple_t *triple ) { const char *begin_token; const char *end_token; char *search_base = NULL; int scope = LDAP_SCOPE_ONELEVEL; char *filter = NULL; const char *s1; __nis_mapping_element_t *element = NULL; /* * The form of the searchTriple is assumed to be as follows: * searchTriple = [baseDN] ["?" [scope] ["?" [filter]]] * baseDN = Base DN for search * scope = "base" | "one" | "sub" * filter = LDAP search filter */ for (; p_error == no_parse_error; ) { while (s < end_s && is_whitespace(*s)) s++; if (s == end_s) break; if (!IS_TERMINAL_CHAR(*s)) { begin_token = s; s = skip_get_dn(begin_token, end_s); if (s == NULL) { p_error = parse_invalid_dn; break; } if (triple != NULL) { search_base = s_strndup(begin_token, s - begin_token); if (search_base == NULL) break; } while (s < end_s && is_whitespace(*s)) s++; if (s == end_s) break; } if (!IS_TERMINAL_CHAR(*s)) { p_error = parse_bad_ldap_item_format; break; } if (*s != QUESTION_MARK) break; s++; while (s < end_s && is_whitespace(*s)) s++; if (s == end_s) break; /* base, one, or sub, or empty value */ if (!IS_TERMINAL_CHAR(*s)) { if ((s1 = skip_string("base", s, end_s - s)) != NULL) { scope = LDAP_SCOPE_BASE; } else if ((s1 = skip_string("one", s, end_s - s)) != NULL) { scope = LDAP_SCOPE_ONELEVEL; } else if ((s1 = skip_string("sub", s, end_s - s)) != NULL) { scope = LDAP_SCOPE_SUBTREE; } else if (s + 1 < end_s && *s != QUESTION_MARK) { p_error = parse_invalid_scope; break; } if (s1 != NULL) s = s1; while (s < end_s && is_whitespace(*s)) s++; } if (s == end_s) break; if (*s != QUESTION_MARK) break; s++; while (s < end_s && is_whitespace(*s)) s++; if (s == end_s || IS_TERMINAL_CHAR(*s)) break; /* LDAP search filter */ if (*s == OPEN_PAREN_CHAR) { begin_token = s; end_token = end_s; s = get_ldap_filter(&begin_token, &end_token); if (s == NULL) break; s = end_token; element = get_ldap_filter_element(begin_token, end_token); if (element != NULL) break; } else { begin_token = s; end_token = end_s; s = get_ava_list(&begin_token, &end_token, TRUE); if (s == NULL) break; s = end_token; } if (triple != NULL) filter = s_strndup(begin_token, s - begin_token); if (p_error == no_parse_error) break; } if (p_error == no_parse_error && triple != NULL) { triple->base = search_base; triple->scope = scope; triple->attrs = filter; triple->element = element; element = NULL; filter = NULL; search_base = NULL; } if (search_base != NULL) free(search_base); if (filter != NULL) free(filter); if (element != NULL) { free_mapping_element(element); free(element); } return (p_error == no_parse_error ? s : NULL); } /* * FUNCTION: get_mapping_format * * Get the __nis_mapping_format_t from the string * * RETURN VALUE: FALSE if error * TRUE if __nis_mapping_format_t returned * * INPUT: the format string */ static bool_t get_mapping_format( const char *fmt_string, __nis_mapping_format_t **fmt, int *nfmt, int *numItems, bool_t print_mapping) { const char *f = fmt_string; const char *ef; __nis_mapping_format_t *b; __nis_mapping_format_t *base = NULL; int n = 0; int nItems = 0; f = fmt_string; ef = f + strlen(f); base = (__nis_mapping_format_t *) s_calloc(1, sizeof (__nis_mapping_format_t)); if (base == NULL) return (FALSE); base->type = mmt_begin; n++; for (;;) { b = (__nis_mapping_format_t *)s_realloc( base, (n + 1) * sizeof (__nis_mapping_format_t)); if (b == NULL) break; base = b; base[n].type = mmt_end; if (f == ef) { if (nfmt) *nfmt = n + 1; *fmt = base; if (numItems) *numItems = nItems; return (TRUE); } if (print_mapping) f = get_next_print_format_item(f, ef, &base[n]); else f = get_next_extract_format_item(f, ef, &base[n]); if (f == NULL) break; if (base[n].type == mmt_item || base[n].type == mmt_berstring) nItems++; n++; } if (base != NULL) free_mapping_format(base); return (FALSE); } /* * FUNCTION: getIndex * * Returns a string containing the index * * RETURN VALUE: NULL if error * a string containing the index * * INPUT: attribute containing the index */ static char * getIndex(const char **s_cur, const char *s_end) { const char *s = *s_cur + 1; const char *s1; char *s_index; char *s_index1; char *s_index_end; int n_brackets = 1; bool_t in_quotes = FALSE; char *index = NULL; while (s < s_end && is_whitespace(*s)) s++; for (s1 = s; s1 < s_end; s1++) { if (*s1 == ESCAPE_CHAR) s1++; else if (*s1 == DOUBLE_QUOTE_CHAR) { in_quotes = !in_quotes; } else if (in_quotes) ; else if (*s1 == CLOSE_BRACKET) { if (--n_brackets == 0) break; } else if (*s1 == OPEN_BRACKET) n_brackets++; } if (n_brackets == 0) { index = s_strndup(s, s1 - s); if (index != NULL) { s_index_end = index + (s1 - s); s_index1 = index; for (s_index = index; s_index < s_index_end; s_index++) { if (*s_index == ESCAPE_CHAR) { *s_index1++ = *s_index++; } else if (*s_index == DOUBLE_QUOTE_CHAR) { in_quotes = !in_quotes; } else if (!in_quotes && is_whitespace(*s_index)) { continue; } *s_index1++ = *s_index; } *s_index1 = *s_index; s = s1 + 1; while (s < s_end && is_whitespace(*s)) s++; *s_cur = s; } } else p_error = parse_mismatched_brackets; return (index); } /* * FUNCTION: parse_index * * Parse attribute string to get __nis_index_t * * RETURN VALUE: FALSE if error * TRUE if __nis_index_t returned * * INPUT: the attribute value to parse */ bool_t parse_index(const char *s, const char *end_s, __nis_index_t *index) { const char *begin_token; const char *end_token; char *name_str = NULL; char **name; char *fmt_string = NULL; __nis_mapping_format_t *v = NULL; __nis_mapping_format_t **value; token_type t; int n = 0; if (index != NULL) (void) memset(index, 0, sizeof (*index)); while (s < end_s) { if (n > 0) { s = skip_token(s, end_s, comma_token); if (s == NULL) { p_error = parse_bad_index_format; break; } } begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; if (t != string_token) { p_error = parse_bad_index_format; break; } s = skip_token(s, end_s, equal_token); if (s == NULL) { p_error = parse_bad_index_format; break; } if (index != NULL) { name_str = s_strndup_esc(begin_token, end_token - begin_token); if (name_str == NULL) break; } begin_token = s; end_token = end_s; s = get_next_token(&begin_token, &end_token, &t); if (s == NULL) break; if (t != string_token && t != quoted_string_token) { p_error = parse_bad_index_format; break; } fmt_string = s_strndup(begin_token, end_token - begin_token); if (fmt_string == NULL) break; if (!get_mapping_format(fmt_string, &v, NULL, NULL, FALSE)) break; free(fmt_string); fmt_string = NULL; if (index != NULL) { name = s_realloc(index->name, (n + 1) * sizeof (char *)); if (name == NULL) break; value = s_realloc(index->value, (n + 1) * sizeof (__nis_mapping_format_t *)); if (value == NULL) break; name[n] = name_str; name_str = NULL; value[n] = v; v = NULL; index->numIndexes = ++n; index->name = name; index->value = value; } else if (v != NULL) { free_mapping_format(v); v = NULL; } } if (p_error != no_parse_error) { if (name_str != NULL) free(name_str); if (v != NULL) free_mapping_format(v); if (fmt_string != NULL) free(fmt_string); if (index != NULL) free_index(index); } return (p_error != no_parse_error); } /* * FUNCTION: get_deleteDisp * * Parse deleteDisp. Sets p_error if an error occurred. * * RETURN VALUE: TRUE on success * FAILURE on failure * * INPUT: begin and end of string and __nis_object_dn_t */ static bool_t get_deleteDisp(const char *s_begin, const char *s_end, __nis_object_dn_t *obj_dn) { /* * deleteDisp: "always" | perDbId | "never" * perDbId: "dbid" "=" delDatabaseId */ if (same_string("always", s_begin, s_end - s_begin)) { obj_dn->delDisp = dd_always; } else if (same_string("never", s_begin, s_end - s_begin)) { obj_dn->delDisp = dd_never; } else if ((s_begin = skip_string("dbid", s_begin, s_end - s_begin)) != NULL) { obj_dn->delDisp = dd_perDbId; while (s_begin < s_end && is_whitespace(*s_begin)) s_begin++; if (s_begin == s_end || *s_begin != EQUAL_CHAR) { p_error = parse_object_dn_syntax_error; } else { s_begin++; while (s_begin < s_end && is_whitespace(*s_begin)) s_begin++; while (s_begin < s_end && is_whitespace(s_end[-1])) s_end--; if (s_begin == s_end) { p_error = parse_object_dn_syntax_error; } else { obj_dn->dbIdName = s_strndup(s_begin, s_end - s_begin); } } } else { p_error = parse_object_dn_syntax_error; } return (p_error == no_parse_error); }