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