/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <locale.h>
#include "ldap_parse.h"
#include "nis_parse_ldap_conf.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;
/*
* To avoid cstyle error, we are creating this typedef.
*/
typedef __nis_table_mapping_t ntm;
/*
* 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;
const char *end_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_unexp_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_unexp_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 = NULL;
} 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:
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:
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:
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:
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:
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_err;
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;
int i;
char *tmp_str;
int ret = 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_unexp_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_nis;
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_unexp_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_unexp_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_unexp_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_err;
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_err;
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_nis);
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_nis : 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_unexp_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_unexp_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_err;
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_fmt_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_unexp_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]
*
* 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
*
*/
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_nis;
} else {
item->type = type;
begin_token = s;
}
} else {
if ((begin_token = skip_string("ldap:", s,
len)) != NULL) {
item->type = mit_ldap;
} 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_nis) {
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_unexp_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_unexp_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 (ntm));
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_err;
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_nis);
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);
}