1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 #include <stdio.h>
  30 #include <string.h>
  31 #include <stdlib.h>
  32 #include <ctype.h>
  33 #include <fcntl.h>
  34 #include <unistd.h>
  35 #include <locale.h>
  36 
  37 #include "ldap_parse.h"
  38 #include "nis_parse_ldap_conf.h"
  39 
  40 /* other attribute functions */
  41 static char *getIndex(const char **s_cur, const char *end_s);
  42 static bool_t get_ttls(const char *s, const char *s_end,
  43     __nis_table_mapping_t *t_mapping);
  44 static __nis_object_dn_t *parse_object_dn(const char *s, const char *end);
  45 static int      parse_name_fields(const char *name_s, const char *name_s_end,
  46         __nis_table_mapping_t *t_mapping);
  47 static void get_mapping_rule(const char *s, int len,
  48     __nis_table_mapping_t *tbl, bool_t to_ldap);
  49 static bool_t get_deleteDisp(const char *s_begin, const char *s_end,
  50     __nis_object_dn_t *obj_dn);
  51 
  52 /* mapping rule functions */
  53 static const char *get_lhs(const char *s, const char *end_s,
  54     __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type);
  55 static const char *get_lhs_match(const char *s, const char *end_s,
  56     __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type);
  57 static const char *get_lhs_paren_item(const char *s, const char *end_s,
  58     __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type);
  59 static const char *get_rhs(const char *s, const char *end_s,
  60     __nis_mapping_rlhs_t *lhs, __nis_mapping_item_type_t item_type);
  61 static const char *get_mapping_item(const char *s, const char *end_s,
  62     __nis_mapping_item_t *item, __nis_mapping_item_type_t type);
  63 static const char *get_print_mapping_element(const char *s,
  64     const char *end_s, char *fmt_string, __nis_mapping_element_t *e,
  65     __nis_mapping_item_type_t item_type);
  66 static const char *get_subElement(const char *s, const char *end_s,
  67     __nis_mapping_sub_element_t *subelement,
  68     __nis_mapping_item_type_t type);
  69 static bool_t get_mapping_format(const char *fmt_string,
  70     __nis_mapping_format_t **fmt, int *nfmt, int *numItems,
  71     bool_t print_mapping);
  72 extern __yp_domain_context_t ypDomains;
  73 
  74 /*
  75  * FUNCTION:    add_mapping_attribute
  76  *
  77  *      Adds the attribute value to __nis_table_mapping_t
  78  *      if the value is not yet set for the given database.
  79  *
  80  * RETURN VALUE:        0 on success, -1 on failure
  81  *
  82  * INPUT:               attribute number and value
  83  */
  84 
  85 int
  86 add_mapping_attribute(
  87         config_key              attrib_num,
  88         const char              *attrib_val,
  89         int                     attrib_len,
  90         __nis_table_mapping_t   **table_mapping)
  91 {
  92         const char              *s;
  93         const char              *attrib_end;
  94         const char              *db_id_end;
  95         const char              *begin_token;
  96         const char              *end_token;
  97         char                    *index_string;
  98         __nis_object_dn_t       *objectDN;
  99         __nis_table_mapping_t   *t_mapping;
 100         __nis_table_mapping_t   *t;
 101 
 102         bool_t                  new_mapping     = FALSE;
 103         int                             nm;
 104         char                    *tmp_dbId;
 105 
 106         attrib_end = attrib_val + attrib_len;
 107         for (s = attrib_val; s < attrib_end; s++)
 108                 if (*s == COLON_CHAR)
 109                         break;
 110 
 111         if (s == attrib_end || *attrib_val == COLON_CHAR) {
 112                 p_error = parse_unexpected_data_end_rule;
 113                 return (-1);
 114         }
 115 
 116         db_id_end = s;
 117         while (s > attrib_val && is_whitespace(s[-1]))
 118                 s--;
 119 
 120         if (s == attrib_val) {
 121                 p_error = parse_unexpected_data_end_rule;
 122                 return (-1);
 123         }
 124 
 125         if (yp2ldap) {
 126                 tmp_dbId = s_strndup(attrib_val, s - attrib_val);
 127                 if (tmp_dbId == NULL) {
 128                         p_error = parse_no_mem_error;
 129                         return (-1);
 130                 }
 131                 if (strchr(tmp_dbId, COMMA_CHAR)) {
 132                         /* domain explicitly specified */
 133                         nm = check_domain_specific_order(tmp_dbId,
 134                                 attrib_num, *table_mapping, &ypDomains);
 135                         /*
 136                          * No logging is needed here, as
 137                          * check_domain_specific_order
 138                          * will log any appropriate errors.
 139                          */
 140                         if (nm != 0) {
 141                                 free(tmp_dbId);
 142                                 return (-1);
 143                         }
 144                 }
 145                 free(tmp_dbId);
 146         }
 147 
 148         if ((t_mapping = find_table_mapping(attrib_val,
 149                         s - attrib_val, *table_mapping)) == NULL) {
 150                 /* No mapping with this id, create one */
 151                 t_mapping = (__nis_table_mapping_t *)
 152                         s_calloc(1, sizeof (__nis_table_mapping_t));
 153 
 154                 if (t_mapping == NULL) {
 155                         p_error = parse_no_mem_error;
 156                         return (-1);
 157                 }
 158                 (void) initialize_table_mapping(t_mapping);
 159 
 160                 /* dbId is the label before the colon */
 161                 t_mapping->dbId = s_strndup(attrib_val, s - attrib_val);
 162                 if (t_mapping->dbId == NULL) {
 163                         p_error = parse_no_mem_error;
 164                         free(t_mapping);
 165                         return (-1);
 166                 }
 167                 new_mapping = TRUE;
 168         } else {
 169                 /* a table mapping already exists, use it */
 170                 new_mapping = FALSE;
 171         }
 172 
 173         s = db_id_end + 1;
 174         while (s < attrib_end && is_whitespace(*s))
 175                 s++;
 176 
 177         switch (attrib_num) {
 178                 case key_yp_map_flags:
 179                         if (t_mapping->usedns_flag != 0 ||
 180                                 t_mapping->securemap_flag != 0) {
 181                                 warn_duplicate_map(t_mapping->dbId,
 182                                         attrib_num);
 183                                 break;
 184                         }
 185                         while (is_whitespace(*s) && s < attrib_end)
 186                                 s++;
 187                         while (s < attrib_end) {
 188                                 if (s < attrib_end && *s == 'b')
 189                                         t_mapping->usedns_flag = 1;
 190                                 if (s < attrib_end && *s == 's')
 191                                         t_mapping->securemap_flag = 1;
 192                                 s++;
 193                         }
 194                         break;
 195                 case key_yp_comment_char:
 196                         if (t_mapping->commentChar !=
 197                                 DEFAULT_COMMENT_CHAR) {
 198                                 warn_duplicate_map(t_mapping->dbId, attrib_num);
 199                                 break;
 200                         }
 201                         while (is_whitespace(*s) && s < attrib_end)
 202                                 s++;
 203                         if (s < attrib_end && (s+1) < attrib_end &&
 204                                 (s+2) <= attrib_end) {
 205                                 while (is_whitespace(attrib_end[-1]))
 206                                         attrib_end--;
 207                                 while (*s != SINGLE_QUOTE_CHAR)
 208                                         s++;
 209                                 if (*s == SINGLE_QUOTE_CHAR &&
 210                                         *(s+2) == SINGLE_QUOTE_CHAR) {
 211                                         t_mapping->commentChar = *(s+1);
 212                                 } else if (*s == SINGLE_QUOTE_CHAR &&
 213                                         *(s+1) == SINGLE_QUOTE_CHAR) {
 214                                         t_mapping->commentChar = NULL;
 215                                 } else {
 216                                         /* anything else is an error */
 217                                         p_error = parse_bad_yp_comment_error;
 218                                 }
 219                                 break;
 220                         } else {
 221                                 p_error = parse_bad_yp_comment_error;
 222                                 break;
 223                         }
 224                 case key_yp_repeated_field_separators:
 225                         while (s < attrib_end && is_whitespace(*s))
 226                                 s++;
 227                         if (s < attrib_end) {
 228                                 while (is_whitespace(attrib_end[-1]))
 229                                         attrib_end--;
 230                                 while (s < attrib_end &&
 231                                                 *s != DOUBLE_QUOTE_CHAR)
 232                                         s++;
 233                                 s++;
 234                                 begin_token = s;
 235                                 while (s < attrib_end &&
 236                                                 *s != DOUBLE_QUOTE_CHAR) {
 237                                         if (*s == ESCAPE_CHAR)
 238                                                 s++;
 239                                         s++;
 240                                 }
 241                                 t_mapping->separatorStr =
 242                                         s_strndup(begin_token, s - begin_token);
 243                                 if (t_mapping->separatorStr == NULL)
 244                                         break;
 245                         } else {
 246                                 p_error = parse_bad_field_separator_error;
 247                         }
 248                         break;
 249                 case key_yp_name_fields:
 250                 case key_yp_split_field:
 251                         if (t_mapping->e || t_mapping->numSplits > 0) {
 252                                 warn_duplicate_map(t_mapping->dbId,
 253                                         attrib_num);
 254                                 break;
 255                         }
 256                         if (parse_name_fields(s, attrib_end, t_mapping)) {
 257                                 p_error = parse_bad_name_field;
 258                         }
 259                         break;
 260                 case key_yp_db_id_map:
 261                 case key_db_id_map:
 262                         if (t_mapping->objName != NULL) {
 263                                 warn_duplicate_map(t_mapping->dbId, attrib_num);
 264                                 break;
 265                         }
 266 
 267                         if (s < attrib_end && *s == OPEN_BRACKET) {
 268                                 index_string = getIndex(&s, attrib_end);
 269                                 if (index_string == NULL)
 270                                         break;
 271                                 (void) parse_index(index_string,
 272                                         index_string + strlen(index_string),
 273                                         &t_mapping->index);
 274                                 free(index_string);
 275                                 if (p_error != no_parse_error)
 276                                         break;
 277                         }
 278                         while (is_whitespace(*s) && s < attrib_end)
 279                                 s++;
 280                         if (s < attrib_end) {
 281                                 while (is_whitespace(attrib_end[-1]))
 282                                         attrib_end--;
 283                                 t_mapping->objName =
 284                                         s_strndup_esc(s, attrib_end - s);
 285                         } else {
 286                                 if (yp2ldap) {
 287                                         p_error = parse_bad_map_error;
 288                                 } else {
 289                                         t_mapping->objName = s_strndup(s, 0);
 290                                 }
 291                         }
 292                         break;
 293 
 294                 case key_yp_entry_ttl:
 295                 case key_entry_ttl:
 296                         if (t_mapping->initTtlLo != (time_t)NO_VALUE_SET) {
 297                                 warn_duplicate_map(t_mapping->dbId, attrib_num);
 298                                 break;
 299                         }
 300 
 301                         if (!get_ttls(s, attrib_end, t_mapping))
 302                                 p_error = parse_bad_ttl_format_error;
 303                         break;
 304 
 305                 case key_yp_ldap_object_dn:
 306                 case key_ldap_object_dn:
 307                         if (t_mapping->objectDN != NULL) {
 308                                 warn_duplicate_map(t_mapping->dbId, attrib_num);
 309                                 break;
 310                         }
 311                         objectDN = parse_object_dn(s, attrib_end);
 312                         if (objectDN == NULL)
 313                                 break;
 314                         t_mapping->objectDN = objectDN;
 315                         t_mapping->seq_num = seq_num++;
 316                         break;
 317 
 318                 case key_nis_to_ldap_map:
 319                 case key_nisplus_to_ldap_map:
 320                         if (t_mapping->ruleToLDAP != 0) {
 321                                 warn_duplicate_map(t_mapping->dbId, attrib_num);
 322                                 break;
 323                         }
 324 
 325                         get_mapping_rule(s, attrib_end - s, t_mapping, TRUE);
 326                         break;
 327 
 328                 case key_ldap_to_nis_map:
 329                 case key_ldap_to_nisplus_map:
 330                         if (t_mapping->ruleFromLDAP != NULL) {
 331                                 warn_duplicate_map(t_mapping->dbId, attrib_num);
 332                                 break;
 333                         }
 334 
 335                         get_mapping_rule(s, attrib_end - s, t_mapping, FALSE);
 336                         break;
 337 
 338                 default:
 339                         p_error = parse_internal_error;
 340                         break;
 341         }
 342         if (p_error == no_parse_error) {
 343                 if (new_mapping) {
 344                         if (*table_mapping == NULL)
 345                                 *table_mapping = t_mapping;
 346                         else {
 347                                 for (t = *table_mapping; t->next != NULL;
 348                                     t = t->next)
 349                                         ;
 350                                 t->next = t_mapping;
 351                         }
 352                 }
 353         } else {
 354                 if (new_mapping)
 355                         free_table_mapping(t_mapping);
 356         }
 357         return (p_error == no_parse_error ? 0 : -1);
 358 }
 359 
 360 /*
 361  * FUNCTION:    add_ypdomains_attribute
 362  *
 363  * Adds the yp domains information to the __yp_domain_context_t
 364  * structure.
 365  *
 366  * RETURN:              0 on success, -1 on failure
 367  *
 368  * INPUT:               attribute number and value
 369  */
 370 
 371 int
 372 add_ypdomains_attribute(
 373         config_key              attrib_num,
 374         const char              *attrib_val,
 375         int                             attrib_len,
 376         __yp_domain_context_t   *ypDomains)
 377 {
 378         const char              *s;
 379         const char              *attrib_end;
 380         int                             numDomains = 0;
 381         int                     i;
 382         char                    *tmp_str;
 383         int                             ret = 0;
 384 
 385         attrib_end = attrib_val + attrib_len;
 386         for (s = attrib_val; s < attrib_end; s++) {
 387                 if (*s == COLON_CHAR) {
 388                         break;
 389                 }
 390         }
 391         while (s > attrib_val && is_whitespace(s[-1]))
 392                 s--;
 393 
 394         if (s == attrib_val) {
 395                 p_error = parse_unexpected_data_end_rule;
 396                 return (-1);
 397         }
 398 
 399         if (ypDomains == NULL) {
 400                 /*
 401                  * No point allocating. We cant return the resulting structure,
 402                  * so just return failure. Should not ever happen because we
 403                  * are always called with a pointer to the global ypDomains
 404                  * structure.
 405                  */
 406                 return (-1);
 407         }
 408 
 409         switch (attrib_num) {
 410                 case key_yp_domain_context:
 411                         numDomains = ypDomains->numDomains;
 412                         ypDomains->domainLabels =
 413                                 (char **)s_realloc(ypDomains->domainLabels,
 414                                 (numDomains + 1) *
 415                                 sizeof (ypDomains->domainLabels[0]));
 416                         if (ypDomains->domainLabels == NULL) {
 417                                 p_error = parse_no_mem_error;
 418                                 free_yp_domain_context(ypDomains);
 419                                 break;
 420                         }
 421                         ypDomains->domainLabels[numDomains] =
 422                                 s_strndup(attrib_val, s - attrib_val);
 423                         if (ypDomains->domainLabels[numDomains] == NULL) {
 424                                 p_error = parse_no_mem_error;
 425                                 free_yp_domain_context(ypDomains);
 426                                 break;
 427                         }
 428                         ypDomains->numDomains = numDomains + 1;
 429                         while (s < attrib_end && is_whitespace(*s))
 430                                 s++;
 431                         if (*s == COLON_CHAR)
 432                                 s++;
 433                         while (s < attrib_end && is_whitespace(*s))
 434                                 s++;
 435                         ypDomains->domains =
 436                                 (char **)s_realloc(ypDomains->domains,
 437                                 (numDomains + 1) *
 438                                 sizeof (ypDomains->domains[0]));
 439                         if (ypDomains->domains == NULL) {
 440                                 p_error = parse_no_mem_error;
 441                                 free_yp_domain_context(ypDomains);
 442                                 break;
 443                         }
 444 
 445                         if (s < attrib_end) {
 446                                 while (is_whitespace(attrib_end[-1]))
 447                                         attrib_end--;
 448                                 ypDomains->domains[numDomains] =
 449                                         s_strndup_esc(s, attrib_end - s);
 450                                 if (ypDomains->domains[numDomains] == NULL) {
 451                                         p_error = parse_no_mem_error;
 452                                         free_yp_domain_context(ypDomains);
 453                                         break;
 454                                 }
 455                         } else {
 456                                 p_error = parse_unexpected_yp_domain_end_error;
 457                                 free(ypDomains->domainLabels[numDomains]);
 458                                 ypDomains->domainLabels[numDomains] = NULL;
 459                                 ypDomains->numDomains--;
 460                                 free_yp_domain_context(ypDomains);
 461                         }
 462                         break;
 463                 case key_yppasswdd_domains:
 464                         ypDomains->yppasswddDomainLabels =
 465                                 (char **)s_realloc(
 466                                 ypDomains->yppasswddDomainLabels,
 467                                 (ypDomains->numYppasswdd + 1) *
 468                                 sizeof (ypDomains->yppasswddDomainLabels[0]));
 469                         if (ypDomains->yppasswddDomainLabels == NULL) {
 470                                 p_error = parse_no_mem_error;
 471                                 break;
 472                         }
 473                         ypDomains->yppasswddDomainLabels
 474                                 [ypDomains->numYppasswdd] =
 475                                 s_strndup(attrib_val, s - attrib_val);
 476                         if (ypDomains->yppasswddDomainLabels
 477                                 [ypDomains->numYppasswdd] == NULL) {
 478                                 p_error = parse_no_mem_error;
 479                         }
 480                         ypDomains->numYppasswdd++;
 481                         break;
 482         }
 483 
 484         return (p_error == no_parse_error ? 0 : -1);
 485 }
 486 
 487 /*
 488  * FUNCTION:    get_ttls
 489  *
 490  *      Parse time to live attribute
 491  *
 492  * RETURN VALUE:        TRUE on success, FALSE on failure
 493  *
 494  * INPUT:               the attribute value
 495  */
 496 
 497 static bool_t
 498 get_ttls(
 499         const char              *s,
 500         const char              *s_end,
 501         __nis_table_mapping_t   *t_mapping)
 502 {
 503         time_t          initTtlHi       = 0;
 504         time_t          initTtlLo       = 0;
 505         time_t          ttl             = 0;
 506         time_t          digit;
 507 
 508         /*
 509          * attribute should be of the form
 510          * initialTTLlo ":" initialTTLhi ":" runningTTL
 511          */
 512 
 513         if (s == s_end) {
 514                 p_error = parse_bad_ttl_format_error;
 515                 return (FALSE);
 516         }
 517 
 518         if (isdigit(*s)) {
 519                 while (s < s_end && isdigit(*s)) {
 520                         digit = (*s++) - '0';
 521                         if (WILL_OVERFLOW_TIME(initTtlLo, digit))
 522                                 initTtlLo = TIME_MAX;
 523                         else
 524                                 initTtlLo = initTtlLo * 10 + digit;
 525                 }
 526         } else {
 527                 initTtlLo = ONE_HOUR;
 528         }
 529 
 530         while (s < s_end && is_whitespace(*s))
 531                 s++;
 532         if (s + 1 >= s_end || *s++ != COLON_CHAR) {
 533                 p_error = parse_bad_ttl_format_error;
 534                 return (FALSE);
 535         }
 536 
 537         while (s < s_end && is_whitespace(*s))
 538                 s++;
 539         if (isdigit(*s)) {
 540                 while (s < s_end && isdigit(*s)) {
 541                         digit = (*s++) - '0';
 542                         if (WILL_OVERFLOW_TIME(initTtlHi, digit))
 543                                 initTtlHi = TIME_MAX;
 544                         else
 545                                 initTtlHi = initTtlHi * 10 + digit;
 546                 }
 547         } else {
 548                 initTtlHi = initTtlLo;
 549         }
 550 
 551         while (s < s_end && is_whitespace(*s))
 552                 s++;
 553         if (s >= s_end || *s++ != COLON_CHAR) {
 554                 p_error = parse_bad_ttl_format_error;
 555                 return (FALSE);
 556         }
 557 
 558         while (s < s_end && is_whitespace(*s))
 559                 s++;
 560         if (isdigit(*s)) {
 561                 while (s < s_end && isdigit(*s)) {
 562                         digit = (*s++) - '0';
 563                         if (WILL_OVERFLOW_TIME(ttl, digit))
 564                                 ttl = TIME_MAX;
 565                         else
 566                                 ttl = ttl * 10 + digit;
 567                 }
 568         } else {
 569                 ttl = ONE_HOUR;
 570         }
 571         while (s < s_end && is_whitespace(*s))
 572                 s++;
 573         if (s != s_end) {
 574                 p_error = parse_bad_ttl_format_error;
 575                 return (FALSE);
 576         }
 577 
 578         t_mapping->initTtlLo = initTtlLo;
 579         t_mapping->initTtlHi = initTtlHi;
 580         t_mapping->ttl = ttl;
 581         return (TRUE);
 582 }
 583 
 584 /*
 585  * FUNCTION:    parse_name_fields
 586  *
 587  * Parse yp name fields
 588  *
 589  * RETURN VALUE:        0 on success, non-zero on failure
 590  *
 591  * INPUTS:              attrib_value and attribute_end pointers.
 592  */
 593 
 594 static int
 595 parse_name_fields(const char *name_s,
 596         const char *name_s_end,
 597         __nis_table_mapping_t   *t_map)
 598 {
 599         int     i, n = 0;
 600         int nElements = 0;
 601         int numSplits = 0;
 602         int parse_next_line = 1;
 603         int itm_count = 0;
 604         const char      *begin_fmt;
 605         const char      *end_fmt;
 606         const char      *begin_token;
 607         const char      *end_token;
 608         char    *fmt_string = NULL;
 609         __nis_mapping_format_t  *base = NULL;
 610         __nis_mapping_item_t    *item = NULL;
 611         __nis_mapping_element_t *elmnt = NULL;
 612         __nis_mapping_item_type_t   item_type = mit_nisplus;
 613         token_type      token;
 614 
 615         t_map->numColumns = 0;
 616 
 617         for (; parse_next_line > 0; parse_next_line--) {
 618                 nElements = 0;
 619                 item = NULL;
 620                 base = NULL;
 621                 while (name_s < name_s_end && *name_s != OPEN_PAREN_CHAR)
 622                         name_s++;
 623                 if (name_s == name_s_end) {
 624                         p_error = parse_unexpected_data_end_rule;
 625                         return (1);
 626                 }
 627                 while (name_s < name_s_end && *name_s != DOUBLE_QUOTE_CHAR)
 628                         name_s++;
 629                 if (name_s == name_s_end) {
 630                         p_error = parse_unexpected_data_end_rule;
 631                         return (1);
 632                 }
 633                 begin_fmt = ++name_s; /* start of format string */
 634                 while (name_s < name_s_end && *name_s != DOUBLE_QUOTE_CHAR)
 635                         name_s++;
 636                 if (name_s == name_s_end) {
 637                         p_error = parse_unexpected_data_end_rule;
 638                         return (1);
 639                 }
 640                 end_fmt = name_s;
 641                 fmt_string = s_strndup(begin_fmt, end_fmt - begin_fmt);
 642                 if (fmt_string == NULL) {
 643                         p_error = parse_no_mem_error;
 644                         return (2);
 645                 }
 646                 if (!get_mapping_format(fmt_string, &base, &n, NULL, FALSE)) {
 647                         p_error = parse_internal_error;
 648                         free(fmt_string);
 649                         fmt_string = NULL;
 650                         return (3);
 651                 }
 652                 free(fmt_string);
 653                 fmt_string = NULL;
 654                 for (n = 0; base[n].type != mmt_end; n++) {
 655                         if (base[n].type != mmt_item && base[n].type
 656                                 != mmt_berstring) {
 657                                 if (base[n].type == mmt_berstring_null)
 658                                         base[n].type = mmt_berstring;
 659                                 continue;
 660                         }
 661                         while (name_s < name_s_end && *name_s != COMMA_CHAR)
 662                                 name_s++;
 663                         name_s++;    /* now at comma char */
 664                         while (name_s < name_s_end && is_whitespace(*name_s))
 665                                 name_s++;
 666                         begin_token = name_s++;
 667                         end_token = name_s_end;
 668                         name_s = get_next_token(
 669                                 &begin_token, &end_token, &token);
 670                         if (name_s == NULL) {
 671                                 p_error = parse_item_expected_error;
 672                                 return (4);
 673                         }
 674                         if (token != string_token) {
 675                                 p_error = parse_item_expected_error;
 676                                 return (5);
 677                         }
 678                         item = (__nis_mapping_item_t *)s_realloc(item,
 679                                 (nElements + 1) *
 680                                 sizeof (__nis_mapping_item_t));
 681                         if (item == NULL) {
 682                                 p_error = parse_no_mem_error;
 683                                 return (2);
 684                         }
 685                         name_s = get_mapping_item(begin_token, name_s_end,
 686                                 &item[nElements], item_type);
 687                         if (name_s == NULL) {
 688                                 p_error = parse_unmatched_escape;
 689                                 for (n = 0; n < (nElements + 1); n++)
 690                                         free_mapping_item(&item[n]);
 691                                 free_mapping_format(base);
 692                                 return (4);
 693                         }
 694                         nElements++;
 695                 }
 696                 if (p_error != no_parse_error) {
 697                         for (n = 0; n < (nElements + 1); n++)
 698                                 free_mapping_item(&item[n]);
 699                         free_mapping_format(base);
 700                         return (6);
 701                 }
 702                 name_s = skip_token(name_s, name_s_end, close_paren_token);
 703                 if (name_s == NULL) {
 704                         p_error = parse_close_paren_expected_error;
 705                         for (n = 0; n < (nElements + 1); n++)
 706                                 free_mapping_item(&item[n]);
 707                         free_mapping_format(base);
 708                         return (4);
 709                 }
 710                 while (name_s < name_s_end && is_whitespace(*name_s))
 711                         name_s++;
 712                 if (*name_s == COMMA_CHAR)
 713                         parse_next_line++;
 714 
 715                 if (nElements == 0) {
 716                         p_error = parse_no_match_item;
 717                         for (n = 0; n < (nElements + 1); n++)
 718                                 free_mapping_item(&item[n]);
 719                         free_mapping_format(base);
 720                         return (7);
 721                 }
 722                 elmnt = (__nis_mapping_element_t *)s_realloc(elmnt,
 723                         (numSplits + 1) *
 724                         sizeof (__nis_mapping_element_t));
 725                 if (elmnt == NULL) {
 726                         for (n = 0; n < (nElements + 1); n++)
 727                                 free_mapping_item(&item[n]);
 728                         free_mapping_format(base);
 729                         p_error = parse_no_mem_error;
 730                         return (2);
 731                 }
 732                 elmnt[numSplits].type = me_match;
 733                 elmnt[numSplits].element.match.numItems = nElements;
 734                 elmnt[numSplits].element.match.item = item;
 735                 elmnt[numSplits].element.match.fmt = base;
 736                 item = NULL;
 737                 base = NULL;
 738 
 739                 t_map->e = elmnt;
 740                 t_map->numSplits = numSplits;
 741                 n = t_map->numColumns;
 742 
 743                 for (i = n, itm_count = 0; i < n + nElements; i++) {
 744                         if (t_map->e[numSplits].element.
 745                                 match.item[itm_count].name) {
 746                                 if (!add_column(t_map,
 747                                         t_map->e[numSplits].element.
 748                                         match.item[itm_count].name))
 749                                         return (1);
 750                                 itm_count++;
 751                         } else {
 752                                 p_error = parse_internal_error;
 753                                 for (n = 0; n < (nElements + 1); n++)
 754                                         free_mapping_item(&item[n]);
 755                                 free_mapping_format(base);
 756                                 free_mapping_element(elmnt);
 757                                 return (1);
 758                         }
 759                 }
 760                 numSplits++;
 761         }
 762         elmnt = NULL;
 763 
 764         if (item != NULL) {
 765                 for (n = 0; n < t_map->numColumns; n++) {
 766                         free_mapping_item(&item[n]);
 767                 }
 768                 free(item);
 769         }
 770         if (elmnt != NULL)
 771                 free_mapping_element(elmnt);
 772         if (base != NULL)
 773                 free_mapping_format(base);
 774 
 775         return (p_error == no_parse_error ? 0 : -1);
 776 }
 777 
 778 /*
 779  * FUNCTION:    parse_object_dn
 780  *
 781  *      Parse object dn attribute
 782  *
 783  * RETURN VALUE:        __nis_object_dn_t on success
 784  *                      NULL on failure
 785  *
 786  * INPUT:               the attribute value
 787  */
 788 
 789 static __nis_object_dn_t *
 790 parse_object_dn(const char *s, const char *end)
 791 {
 792         const char              *s_begin;
 793         const char              *s_end;
 794         object_dn_token         token;
 795         parse_object_dn_state   dn_state        = dn_begin_parse;
 796         __nis_object_dn_t       *obj_dn         = NULL;
 797         __nis_object_dn_t       *next           = NULL;
 798         __nis_object_dn_t       *last           = NULL;
 799 
 800         /*
 801          * The attribute should be of form
 802          * objectDN *( ";" objectDN )
 803          * objectDN = readObjectSpec [":"[writeObjectSpec]]
 804          * readObjectSpec = [baseAndScope [filterAttrValList]]
 805          * writeObjectSpec = [baseAndScope [attrValList [":" deleteDisp]]]
 806          */
 807 
 808         while (s < end) {
 809                 s_begin = s;
 810                 s_end = end;
 811                 s = get_next_object_dn_token(&s_begin, &s_end, &token);
 812                 if (s == NULL)
 813                         break;
 814 
 815                 if (token == dn_no_token || token == dn_semi_token) {
 816                         if (obj_dn == NULL)
 817                                 obj_dn = next;
 818                         else
 819                                 last->next = next;
 820                         last = next;
 821                         next = NULL;
 822                         if (token == dn_no_token)
 823                                 break;
 824                         dn_state = dn_begin_parse;
 825                 }
 826                 if (next == NULL) {
 827                         next = (__nis_object_dn_t *)
 828                                 s_calloc(1, sizeof (__nis_object_dn_t));
 829                         if (next == NULL)
 830                                 break;
 831                         next->read.scope = LDAP_SCOPE_ONELEVEL;
 832                         next->write.scope = LDAP_SCOPE_UNKNOWN;
 833                         next->delDisp = dd_always;
 834                 }
 835                 if (token == dn_semi_token)
 836                         continue;
 837 
 838                 switch (dn_state) {
 839                     case dn_begin_parse:
 840                         if (token == dn_ques_token)
 841                                 dn_state = dn_got_read_q_scope;
 842                         else if (token == dn_colon_token) {
 843                                 dn_state = dn_got_write_colon;
 844                                 next->write.scope = LDAP_SCOPE_ONELEVEL;
 845                         } else {
 846                                 if (!validate_dn(s_begin, s_end - s_begin))
 847                                         break;
 848                                 next->read.base =
 849                                         s_strndup_esc(s_begin, s_end - s_begin);
 850                                 dn_state = dn_got_read_dn;
 851                         }
 852                         break;
 853                     case dn_got_read_dn:
 854                         if (token == dn_ques_token)
 855                                 dn_state = dn_got_read_q_scope;
 856                         else if (token == dn_colon_token) {
 857                                 dn_state = dn_got_write_colon;
 858                                 next->write.scope = LDAP_SCOPE_ONELEVEL;
 859                         } else
 860                                 p_error = parse_object_dn_syntax_error;
 861                         break;
 862                     case dn_got_read_q_scope:
 863                         if (token == dn_ques_token)
 864                                 dn_state = dn_got_read_q_filter;
 865                         else if (token == dn_colon_token) {
 866                                 dn_state = dn_got_write_colon;
 867                                 next->write.scope = LDAP_SCOPE_ONELEVEL;
 868                         } else if (token == dn_base_token) {
 869                                 next->read.scope = LDAP_SCOPE_BASE;
 870                                 dn_state = dn_got_read_scope;
 871                         } else if (token == dn_one_token) {
 872                                 next->read.scope = LDAP_SCOPE_ONELEVEL;
 873                                 dn_state = dn_got_read_scope;
 874                         } else if (token == dn_sub_token) {
 875                                 next->read.scope = LDAP_SCOPE_SUBTREE;
 876                                 dn_state = dn_got_read_scope;
 877                         } else {
 878                                 p_error = parse_invalid_scope;
 879                         }
 880                         break;
 881                     case dn_got_read_scope:
 882                         if (token == dn_ques_token)
 883                                 dn_state = dn_got_read_q_filter;
 884                         else if (token == dn_colon_token) {
 885                                 dn_state = dn_got_write_colon;
 886                                 next->write.scope = LDAP_SCOPE_ONELEVEL;
 887                         } else
 888                                 p_error = parse_object_dn_syntax_error;
 889                         break;
 890                     case dn_got_read_q_filter:
 891                         if (token == dn_ques_token) {
 892                                 p_error = parse_object_dn_syntax_error;
 893                         } else if (token == dn_colon_token) {
 894                                 dn_state = dn_got_write_colon;
 895                                 next->write.scope = LDAP_SCOPE_ONELEVEL;
 896                         } else {
 897                                 if (!validate_ldap_filter(s_begin, s_end))
 898                                         break;
 899                                 next->read.attrs =
 900                                         s_strndup_esc(s_begin, s_end - s_begin);
 901                                 dn_state = dn_got_read_filter;
 902                         }
 903                         break;
 904                     case dn_got_read_filter:
 905                         if (token == dn_ques_token) {
 906                                 p_error = parse_object_dn_syntax_error;
 907                         } else if (token == dn_colon_token) {
 908                                 dn_state = dn_got_write_colon;
 909                                 next->write.scope = LDAP_SCOPE_ONELEVEL;
 910                         } else
 911                                 p_error = parse_object_dn_syntax_error;
 912                         break;
 913                     case dn_got_write_colon:
 914                         if (token == dn_ques_token)
 915                                 dn_state = dn_got_write_q_scope;
 916                         else if (token == dn_colon_token) {
 917                                 dn_state = dn_got_delete_colon;
 918                         } else {
 919                                 if (!validate_dn(s_begin, s_end - s_begin))
 920                                         break;
 921                                 next->write.base =
 922                                         s_strndup_esc(s_begin, s_end - s_begin);
 923                                 dn_state = dn_got_write_dn;
 924                         }
 925                         break;
 926                     case dn_got_write_dn:
 927                         if (token == dn_ques_token)
 928                                 dn_state = dn_got_write_q_scope;
 929                         else if (token == dn_colon_token) {
 930                                 dn_state = dn_got_delete_colon;
 931                         } else
 932                                 p_error = parse_object_dn_syntax_error;
 933                         break;
 934                     case dn_got_write_q_scope:
 935                         if (token == dn_ques_token)
 936                                 dn_state = dn_got_write_q_filter;
 937                         else if (token == dn_colon_token) {
 938                                 dn_state = dn_got_delete_colon;
 939                         } else if (token == dn_base_token) {
 940                                 next->write.scope = LDAP_SCOPE_BASE;
 941                                 dn_state = dn_got_write_scope;
 942                         } else if (token == dn_one_token) {
 943                                 next->write.scope = LDAP_SCOPE_ONELEVEL;
 944                                 dn_state = dn_got_write_scope;
 945                         } else if (token == dn_sub_token) {
 946                                 next->write.scope = LDAP_SCOPE_SUBTREE;
 947                                 dn_state = dn_got_write_scope;
 948                         } else {
 949                                 p_error = parse_invalid_scope;
 950                         }
 951                         break;
 952                     case dn_got_write_scope:
 953                         if (token == dn_ques_token)
 954                                 dn_state = dn_got_write_q_filter;
 955                         else if (token == dn_colon_token) {
 956                                 dn_state = dn_got_delete_colon;
 957                         } else
 958                                 p_error = parse_object_dn_syntax_error;
 959                         break;
 960                     case dn_got_write_q_filter:
 961                         if (token == dn_ques_token) {
 962                                 p_error = parse_object_dn_syntax_error;
 963                         } else if (token == dn_colon_token) {
 964                                 dn_state = dn_got_delete_colon;
 965                         } else {
 966                                 if (!validate_ldap_filter(s_begin, s_end))
 967                                         break;
 968                                 next->write.attrs =
 969                                         s_strndup_esc(s_begin, s_end - s_begin);
 970                                 dn_state = dn_got_write_filter;
 971                         }
 972                         break;
 973                     case dn_got_write_filter:
 974                         if (token == dn_ques_token) {
 975                                 p_error = parse_object_dn_syntax_error;
 976                         } else if (token == dn_colon_token) {
 977                                 dn_state = dn_got_delete_colon;
 978 
 979                         } else
 980                                 p_error = parse_semi_expected_error;
 981                         break;
 982                     case dn_got_delete_colon:
 983                         if (token == dn_ques_token) {
 984                                 p_error = parse_object_dn_syntax_error;
 985                         } else if (token == dn_colon_token) {
 986                                 p_error = parse_object_dn_syntax_error;
 987                         } else {
 988                                 if (!get_deleteDisp(s_begin, s_end, next))
 989                                         break;
 990                                 dn_state = dn_got_delete_dsp;
 991                         }
 992                         break;
 993                     case dn_got_delete_dsp:
 994                         p_error = parse_object_dn_syntax_error;
 995                         break;
 996                 }
 997 
 998                 if (p_error != no_parse_error)
 999                         break;
1000         }
1001         if (p_error != no_parse_error) {
1002                 if (obj_dn != NULL)
1003                         free_object_dn(obj_dn);
1004                 if (next != NULL)
1005                         free_object_dn(next);
1006                 obj_dn = NULL;
1007         } else if (next != NULL) {
1008                 if (obj_dn == NULL)
1009                         obj_dn = next;
1010                 else
1011                         last->next = next;
1012         } else if (obj_dn == NULL)
1013                 obj_dn = (__nis_object_dn_t *)
1014                         s_calloc(1, sizeof (__nis_object_dn_t));
1015 
1016         return (obj_dn);
1017 }
1018 
1019 /*
1020  * FUNCTION:    get_mapping_rule
1021  *
1022  *      Parse mapping rule attributes
1023  *
1024  * RETURN VALUE:        None. Errors determined by p_error
1025  *
1026  * INPUT:               the attribute value and mapping rule type
1027  */
1028 
1029 static void
1030 get_mapping_rule(
1031         const char              *s,
1032         int                     len,
1033         __nis_table_mapping_t   *tbl,
1034         bool_t                  to_ldap)
1035 {
1036         const char              *end_s                  = s + len;
1037         const char              *begin_token;
1038         const char              *end_token;
1039         __nis_mapping_rule_t    **rule                  = NULL;
1040         __nis_mapping_rule_t    *next                   = NULL;
1041         /* __nis_mapping_rule_t **r; */
1042         token_type              t;
1043         int                     nRules                  = 0;
1044         const char              *s1;
1045         int                     i;
1046 
1047         /*
1048          * The attribute value is of the form
1049          * colattrspec *("," colattrspec)
1050          * colattrspec  = lhs "=" rhs
1051          * lhs          = lval | namespeclist
1052          * rhs          = rval | [namespec]
1053          */
1054 
1055         for (;;) {
1056                 if ((next = (__nis_mapping_rule_t *)
1057                     s_calloc(1, sizeof (__nis_mapping_rule_t))) == NULL)
1058                         break;
1059 
1060                 s = get_lhs(s, end_s, &next->lhs,
1061                         to_ldap ? mit_ldap : mit_nisplus);
1062                 if (s == NULL)
1063                         break;
1064 
1065                 begin_token = s;
1066                 end_token = end_s;
1067                 s1 = get_next_token(&begin_token, &end_token, &t);
1068                 if (s1 == NULL)
1069                         break;
1070                 if (!(to_ldap && (t == comma_token || t == no_token))) {
1071                         s = get_rhs(s, end_s, &next->rhs,
1072                                 to_ldap ? mit_nisplus : mit_ldap);
1073                         if (s == NULL)
1074                                 break;
1075                 }
1076 
1077                 if (next->lhs.numElements > 1 &&
1078                     (next->rhs.numElements != 1 ||
1079                     next->rhs.element[0].type != me_split)) {
1080                         p_error = parse_lhs_rhs_type_mismatch;
1081                         break;
1082                 }
1083                 if (rule == NULL) {
1084                         rule = (__nis_mapping_rule_t **)
1085                                 malloc(sizeof (__nis_mapping_rule_t *));
1086                         if (rule == NULL)
1087                                 break;
1088                 } else {
1089                         rule = (__nis_mapping_rule_t **)s_realloc(rule,
1090                                 (nRules + 1) *
1091                                 sizeof (__nis_mapping_rule_t *));
1092                         if (rule == NULL)
1093                                 break;
1094                 }
1095 
1096                 rule[nRules++] = next;
1097                 next = NULL;
1098 
1099                 begin_token = s;
1100                 end_token = end_s;
1101                 s = get_next_token(&begin_token, &end_token, &t);
1102                 if (s == NULL)
1103                         break;
1104                 if (t == comma_token)
1105                         continue;
1106                 if (t != no_token) {
1107                         p_error = parse_unexpected_data_end_rule;
1108                         break;
1109                 }
1110                 if (to_ldap) {
1111                         tbl->numRulesToLDAP = nRules;
1112                         tbl->ruleToLDAP = rule;
1113                 } else {
1114                         tbl->numRulesFromLDAP = nRules;
1115                         tbl->ruleFromLDAP = rule;
1116                 }
1117                 return;
1118         }
1119 
1120         if (rule) {
1121                 for (i = 0; i < nRules; i++)
1122                         free_mapping_rule(rule[i]);
1123                 free(rule);
1124         }
1125         if (next)
1126                 free_mapping_rule(next);
1127 }
1128 
1129 /*
1130  * FUNCTION:    get_lhs
1131  *
1132  *      Parse left hand side of mapping rule attribute
1133  *
1134  * RETURN VALUE:        NULL if error
1135  *                      position of beginning rhs
1136  *
1137  * INPUT:               the attribute value and mapping rule type
1138  */
1139 
1140 static const char *
1141 get_lhs(const char                      *s,
1142         const char                      *end_s,
1143         __nis_mapping_rlhs_t            *lhs,
1144         __nis_mapping_item_type_t       item_type)
1145 {
1146         token_type              t;
1147         const char              *begin_token;
1148         const char              *end_token;
1149         const char              *sav_s;
1150         __nis_mapping_element_t *e              = NULL;
1151 
1152         /*
1153          *      lhs can be expressed as:
1154          *              item
1155          *              (item)
1156          *              (item list)
1157          *              (fmt, item list)
1158          *
1159          * lhs = lval | namespeclist
1160          * lval = "(" formatspec "," namespec *("," namespec) ")"
1161          * namespeclist = namespec | "(" namespec *("," namespec) ")"
1162          */
1163 
1164         for (; p_error == no_parse_error; ) {
1165                 begin_token = s;
1166                 end_token = end_s;
1167                 s = get_next_token(&begin_token, &end_token, &t);
1168                 if (s == NULL)
1169                         break;
1170                 if (t == no_token) {
1171                         p_error = parse_unexpected_data_end_rule;
1172                         break;
1173                 }
1174 
1175                 e = (__nis_mapping_element_t *)
1176                         s_calloc(1, sizeof (__nis_mapping_element_t));
1177                 if (e == NULL)
1178                         break;
1179 
1180                 if (t == open_paren_token) {
1181                         free(e);
1182                         e = NULL;
1183 
1184                         begin_token = s;
1185                         end_token = end_s;
1186                         sav_s = s;
1187                         s = get_next_token(&begin_token, &end_token, &t);
1188                         if (s == NULL)
1189                                 break;
1190 
1191                         if (t == quoted_string_token) {
1192                                 s = get_lhs_match(sav_s, end_s, lhs, item_type);
1193                                 if (s == NULL)
1194                                         break;
1195                         } else if (t == string_token) {
1196                                 s = get_lhs_paren_item(sav_s, end_s, lhs,
1197                                         item_type);
1198                                 if (s == NULL)
1199                                         break;
1200                         } else {
1201                                 p_error = parse_bad_lhs_format_error;
1202                                 break;
1203                         }
1204                 } else if (t == string_token) {
1205                         s = get_mapping_item(begin_token, end_s,
1206                                 &e->element.item, item_type);
1207                         if (s == NULL)
1208                                 break;
1209                         e->type = me_item;
1210                         if (!add_element(e, lhs))
1211                                 break;
1212                         e = NULL;
1213                 } else {
1214                         p_error = parse_bad_lhs_format_error;
1215                         break;
1216                 }
1217 
1218                 s = skip_token(s, end_s, equal_token);
1219                 if (s == NULL)
1220                         break;
1221                 if (p_error == no_parse_error)
1222                         return (s);
1223         }
1224         if (e != NULL)
1225                 free_mapping_element(e);
1226 
1227         return (NULL);
1228 }
1229 
1230 /*
1231  * FUNCTION:    get_lhs_match
1232  *
1233  *      Parse left hand side of mapping rule attribute in case of
1234  *      matching rule
1235  *
1236  * RETURN VALUE:        NULL if error
1237  *                      position of beginning rhs
1238  *
1239  * INPUT:               the attribute value and mapping rule type
1240  */
1241 
1242 static const char *
1243 get_lhs_match(
1244         const char                      *s,
1245         const char                      *end_s,
1246         __nis_mapping_rlhs_t            *lhs,
1247         __nis_mapping_item_type_t       item_type)
1248 {
1249         token_type                      t;
1250         const char                      *begin_token;
1251         const char                      *end_token;
1252         int                             n               = 0;
1253         int                             nElements       = 0;
1254         char                            *fmt_string     = NULL;
1255         __nis_mapping_format_t          *base           = NULL;
1256         __nis_mapping_item_t            *item           = NULL;
1257         __nis_mapping_item_t            *itm;
1258         __nis_mapping_element_t         *e;
1259 
1260         /*
1261          *  lval = "(" formatspec "," namespec *("," namespec) ")"
1262          */
1263 
1264         for (; p_error == no_parse_error; ) {
1265                 begin_token = s;
1266                 end_token = end_s;
1267                 s = get_next_token(&begin_token, &end_token, &t);
1268                 if (s == NULL || t != quoted_string_token) {
1269                         p_error = parse_internal_error;
1270                         break;
1271                 }
1272 
1273 
1274                 fmt_string = s_strndup(begin_token, end_token - begin_token);
1275                 if (fmt_string == NULL)
1276                         break;
1277 
1278                 if (!get_mapping_format(fmt_string, &base, &n, NULL, FALSE))
1279                         break;
1280 
1281                 for (n = 0; base[n].type != mmt_end; n++) {
1282                         if (base[n].type != mmt_item &&
1283                             base[n].type != mmt_berstring) {
1284                                 if (base[n].type == mmt_berstring_null)
1285                                         base[n].type = mmt_berstring;
1286                                 continue;
1287                         }
1288                         s = skip_token(s, end_s, comma_token);
1289                         if (s == NULL) {
1290                                 p_error = parse_not_enough_extract_items;
1291                                 break;
1292                         }
1293                         begin_token = s;
1294                         end_token = end_s;
1295                         s = get_next_token(&begin_token, &end_token, &t);
1296                         if (s == NULL)
1297                                 break;
1298                         if (t != string_token) {
1299                                 p_error = parse_item_expected_error;
1300                                 break;
1301                         }
1302                         itm = (__nis_mapping_item_t *)
1303                                 s_realloc(item, (nElements + 1) *
1304                                 sizeof (__nis_mapping_item_t));
1305                         if (itm == NULL)
1306                                 break;
1307                         item = itm;
1308 
1309                         s = get_mapping_item(begin_token, end_s,
1310                                 &item[nElements], item_type);
1311                         if (s == NULL)
1312                                 break;
1313                         nElements++;
1314                 }
1315                 if (p_error != no_parse_error)
1316                         break;
1317 
1318                 s = skip_token(s, end_s, close_paren_token);
1319                 if (s == NULL)
1320                         break;
1321                 free(fmt_string);
1322                 fmt_string = NULL;
1323 
1324                 if (nElements == 0) {
1325                         p_error = parse_no_match_item;
1326                         break;
1327                 }
1328                 e = (__nis_mapping_element_t *)s_calloc(1,
1329                         sizeof (__nis_mapping_element_t));
1330                 if (e == NULL)
1331                         break;
1332                 e->type = me_match;
1333                 e->element.match.numItems = nElements;
1334                 e->element.match.item = item;
1335                 e->element.match.fmt = base;
1336                 lhs->numElements = 1;
1337                 lhs->element = e;
1338 
1339                 if (p_error == no_parse_error)
1340                         return (s);
1341         }
1342         if (item == NULL) {
1343                 for (n = 0; n < nElements; n++)
1344                         free_mapping_item(&item[n]);
1345                 free(item);
1346         }
1347         if (fmt_string != NULL)
1348                 free(fmt_string);
1349         if (base != NULL)
1350                 free_mapping_format(base);
1351 
1352         return (NULL);
1353 }
1354 
1355 /*
1356  * FUNCTION:    get_lhs_paren_item
1357  *
1358  *      Parse left hand side of mapping rule attribute in case of
1359  *      (item1, ..., item-n)
1360  *
1361  * RETURN VALUE:        NULL if error
1362  *                      position of beginning rhs
1363  *
1364  * INPUT:               the attribute value and mapping rule type
1365  */
1366 
1367 static const char *
1368 get_lhs_paren_item(
1369         const char                      *s,
1370         const char                      *end_s,
1371         __nis_mapping_rlhs_t            *lhs,
1372         __nis_mapping_item_type_t       item_type)
1373 {
1374         token_type              t;
1375         const char              *begin_token;
1376         const char              *end_token;
1377         __nis_mapping_element_t *e              = NULL;
1378         int                     n               = 0;
1379         int                     i;
1380 
1381         /*
1382          * "(" namespec *("," namespec) ")"
1383          */
1384 
1385         for (;;) {
1386                 e = (__nis_mapping_element_t *)s_realloc(e, (n + 1) *
1387                         sizeof (__nis_mapping_element_t));
1388                 if (e == NULL)
1389                         break;
1390 
1391                 s = get_mapping_item(s, end_s, &e[n].element.item,
1392                         item_type);
1393                 if (s == NULL)
1394                         break;
1395                 e[n].type = me_item;
1396                 n++;
1397 
1398                 begin_token = s;
1399                 end_token = end_s;
1400                 s = get_next_token(&begin_token, &end_token, &t);
1401                 if (s != NULL && t == close_paren_token) {
1402                         lhs->numElements = n;
1403                         if (n == 1)
1404                                 e[0].element.item.repeat = TRUE;
1405                         lhs->element = e;
1406                         return (s);
1407                 }
1408                 if (s == NULL || t != comma_token) {
1409                         p_error = parse_comma_expected_error;
1410                         break;
1411                 }
1412         }
1413         for (i = 0; i < n; i++)
1414                 free_mapping_element(&e[i]);
1415         if (e != NULL)
1416                 free(e);
1417         return (NULL);
1418 }
1419 
1420 /*
1421  * FUNCTION:    get_rhs
1422  *
1423  *      Parse right hand side of mapping rule attribute
1424  *
1425  * RETURN VALUE:        NULL if error
1426  *                      position of beginning next mapping rule
1427  *
1428  * INPUT:               the attribute value and mapping rule type
1429  */
1430 
1431 static const char *
1432 get_rhs(
1433         const char                      *s,
1434         const char                      *end_s,
1435         __nis_mapping_rlhs_t            *rhs,
1436         __nis_mapping_item_type_t       item_type)
1437 {
1438         /*
1439          * This handles the following cases:
1440          *      name                            me_item
1441          *      (name)                          me_item
1442          *      (fmt, name-list)                me_print
1443          *      (item, fmt)                     me_extract
1444          */
1445 
1446         token_type              t;
1447         const char              *begin_token;
1448         const char              *end_token;
1449         char                    *str            = NULL;
1450         __nis_mapping_format_t  *fmt            = NULL;
1451         __nis_mapping_element_t *e              = NULL;
1452         __nis_mapping_item_t    item;
1453         int                     n;
1454 
1455         (void) memset(&item, 0, sizeof (item));
1456 
1457         for (; p_error == no_parse_error; ) {
1458                 begin_token = s;
1459                 end_token = end_s;
1460                 s = get_next_token(&begin_token, &end_token, &t);
1461                 if (s == NULL)
1462                         break;
1463 
1464                 e = (__nis_mapping_element_t *)
1465                         s_calloc(1, sizeof (__nis_mapping_element_t));
1466                 if (e == NULL)
1467                         break;
1468 
1469                 if (t == string_token) {
1470                         s = get_mapping_item(begin_token, end_s,
1471                                 &e->element.item, item_type);
1472                 } else if (t == open_paren_token) {
1473                         begin_token = s;
1474                         end_token = end_s;
1475                         s = get_next_token(&begin_token, &end_token, &t);
1476                         if (s == NULL)
1477                                 break;
1478                         if (t == string_token) {
1479                                 /* (item, fmt) - me_extract */
1480                                 /* (item, "c") - me_split */
1481                                 s = get_mapping_item(begin_token, end_s,
1482                                         &item, item_type);
1483                                 if (s == NULL)
1484                                         break;
1485                                 begin_token = s;
1486                                 end_token = end_s;
1487                                 s = get_next_token(&begin_token, &end_token,
1488                                         &t);
1489                                 if (s == NULL)
1490                                         break;
1491                                 else if (t == close_paren_token) {
1492                                         item.repeat = TRUE;
1493                                         e->element.item = item;
1494                                         e->type = me_item;
1495                                         rhs->numElements = 1;
1496                                         rhs->element = e;
1497                                         return (s);
1498                                 } else if (t != comma_token) {
1499                                         p_error = parse_comma_expected_error;
1500                                         break;
1501                                 }
1502 
1503                                 begin_token = s;
1504                                 end_token = end_s;
1505                                 s = get_next_token(&begin_token, &end_token,
1506                                         &t);
1507                                 if (s == NULL || t != quoted_string_token) {
1508                                     p_error =
1509                                         parse_format_string_expected_error;
1510                                     break;
1511                                 }
1512 
1513                                 if (end_token == begin_token + 1 ||
1514                                     *begin_token == ESCAPE_CHAR &&
1515                                     end_token == begin_token + 2) {
1516                                         e->type = me_split;
1517                                         e->element.split.item = item;
1518                                         e->element.split.delim = *begin_token;
1519                                 } else {
1520                                         str = s_strndup(begin_token,
1521                                                 end_token - begin_token);
1522                                         if (str == NULL)
1523                                                 break;
1524                                         if (!get_mapping_format(str, &fmt,
1525                                             NULL, &n, FALSE))
1526                                                 break;
1527                                         free(str);
1528                                         str = NULL;
1529                                         if (n != 1) {
1530                                             p_error =
1531                                                 parse_bad_extract_format_spec;
1532                                             break;
1533                                         }
1534                                         e->type = me_extract;
1535                                         e->element.extract.item = item;
1536                                         e->element.extract.fmt = fmt;
1537                                 }
1538                                 s = skip_token(s, end_s, close_paren_token);
1539                         } else if (t == quoted_string_token) {
1540                                 /* (fmt, name-list) - me_print */
1541                                 str = s_strndup(begin_token,
1542                                         end_token - begin_token);
1543                                 if (str == NULL)
1544                                         break;
1545 
1546                                 s = get_print_mapping_element(s, end_s,
1547                                         str, e, item_type);
1548                                 free(str);
1549                                 str = NULL;
1550                         } else {
1551                                 p_error = parse_start_rhs_unrecognized;
1552                                 break;
1553                         }
1554                 } else {
1555                         p_error = parse_start_rhs_unrecognized;
1556                         break;
1557                 }
1558                 if (s == NULL)
1559                         break;
1560                 rhs->numElements = 1;
1561                 rhs->element = e;
1562                 if (p_error == no_parse_error)
1563                         return (s);
1564         }
1565         if (str)
1566                 free(str);
1567         if (fmt != NULL)
1568                 free_mapping_format(fmt);
1569         if (e != NULL)
1570                 free_mapping_element(e);
1571         free_mapping_item(&item);
1572 
1573         return (NULL);
1574 }
1575 
1576 /*
1577  * FUNCTION:    get_print_mapping_element
1578  *
1579  *      Parse a print mapping rule attribute in case of the form
1580  *      (fmt, name-list)
1581  *
1582  * RETURN VALUE:        NULL if error
1583  *                      position of beginning next mapping rule
1584  *
1585  * INPUT:               the attribute value and mapping rule type
1586  */
1587 
1588 static const char *
1589 get_print_mapping_element(
1590         const char                      *s,
1591         const char                      *end_s,
1592         char                            *fmt_string,
1593         __nis_mapping_element_t         *e,
1594         __nis_mapping_item_type_t       item_type)
1595 {
1596         token_type                      t;
1597         const char                      *begin_token;
1598         const char                      *end_token;
1599         char                            elide;
1600         bool_t                          doElide;
1601         __nis_mapping_format_t          *base           = NULL;
1602         __nis_mapping_sub_element_t     *subElement     = NULL;
1603         int                             n               = 0;
1604         int                             nSub            = 0;
1605         int                             numSubElements;
1606 
1607         for (; p_error == no_parse_error; ) {
1608                 if (!get_mapping_format(fmt_string, &base, &n,
1609                     &numSubElements, TRUE))
1610                         break;
1611                 subElement = (__nis_mapping_sub_element_t *)
1612                         s_calloc(numSubElements,
1613                         sizeof (__nis_mapping_sub_element_t));
1614                 if (subElement == NULL)
1615                         break;
1616                 for (n = 0; base[n].type != mmt_end; n++) {
1617                         if (base[n].type != mmt_item &&
1618                                 base[n].type != mmt_berstring) {
1619                             if (base[n].type == mmt_berstring_null)
1620                                 base[n].type = mmt_berstring;
1621                             continue;
1622                         }
1623                         if (nSub < numSubElements) {
1624                                 s = skip_token(s, end_s, comma_token);
1625                                 if (s == NULL) {
1626                                         p_error = parse_bad_print_format;
1627                                         break;
1628                                 }
1629                         }
1630 
1631                         /* namelist may have parens around it */
1632                         s = get_subElement(s, end_s, &subElement[nSub],
1633                                 item_type);
1634                         if (s == NULL)
1635                                 break;
1636                         nSub++;
1637                 }
1638                 if (p_error != no_parse_error)
1639                         break;
1640 
1641                 begin_token = s;
1642                 end_token = end_s;
1643                 s = get_next_token(&begin_token, &end_token, &t);
1644                 if (s == NULL || t == no_token) {
1645                         p_error = parse_unexpected_data_end_rule;
1646                         break;
1647                 } else if (t == close_paren_token) {
1648                         doElide = FALSE;
1649                         elide = '\0';
1650                 } else if (t == comma_token) {
1651                         begin_token = s;
1652                         end_token = end_s;
1653                         s = get_next_token(&begin_token, &end_token, &t);
1654                         if (s != NULL && t == quoted_string_token &&
1655                                 (end_token == begin_token + 1 ||
1656                                     *begin_token == ESCAPE_CHAR &&
1657                                     end_token == begin_token + 2)) {
1658                                 if (numSubElements != 1 ||
1659                                     subElement->type == me_extract ||
1660                                     subElement->type == me_split) {
1661                                         p_error = parse_cannot_elide;
1662                                         break;
1663                                 }
1664                                 if (subElement->type == me_item &&
1665                                     !subElement->element.item.repeat) {
1666                                         p_error = parse_cannot_elide;
1667                                         break;
1668                                 }
1669                                 elide = *begin_token;
1670                                 doElide = TRUE;
1671 
1672                         } else {
1673                                 p_error = parse_bad_elide_char;
1674                                 break;
1675                         }
1676                         s = skip_token(s, end_s, close_paren_token);
1677                         if (s == NULL)
1678                                 break;
1679                 }
1680 
1681                 e->type = me_print;
1682                 e->element.print.fmt = base;
1683                 e->element.print.numSubElements = numSubElements;
1684                 e->element.print.subElement = subElement;
1685                 e->element.print.elide = elide;
1686                 e->element.print.doElide = doElide;
1687 
1688                 if (p_error == no_parse_error)
1689                         return (s);
1690         }
1691         if (base)
1692                 free_mapping_format(base);
1693         if (subElement != NULL) {
1694                 for (n = 0; n < numSubElements; n++)
1695                         free_mapping_sub_element(&subElement[n]);
1696                 free(subElement);
1697         }
1698 
1699         return (NULL);
1700 }
1701 
1702 /*
1703  * FUNCTION:    get_mapping_item
1704  *
1705  *      Parse attribute string to get mapping item
1706  *
1707  * RETURN VALUE:        NULL if error
1708  *                      position of beginning next token after item
1709  *
1710  * INPUT:               the attribute value and mapping rule type
1711  */
1712 
1713 static const char *
1714 get_mapping_item(
1715         const char                      *s,
1716         const char                      *end_s,
1717         __nis_mapping_item_t            *item,
1718         __nis_mapping_item_type_t       type)
1719 {
1720         token_type                      t;
1721         const char                      *begin_token;
1722         const char                      *end_token;
1723         char                            *name           = NULL;
1724         char                            *index_string;
1725         const char                      *s_sav;
1726         int                             len;
1727 
1728         (void) memset(item, 0, sizeof (*item));
1729 
1730         /*
1731          * A namepec is defined as follows:
1732          * namespec     = ["ldap:"] attrspec [searchTriple] |
1733          *                ["nis+:"] colspec  [objectspec]
1734          *
1735          * The form of the item is assumed to be as follows:
1736          * ["ldap:"] attrspec [searchTriple]
1737          * attrspec = attribute | "(" attribute ")"
1738          * searchTriple = ":" [baseDN] ["?" [scope] ["?" [filter]]]
1739          * baseDN = Base DN for search
1740          * scope = "base" | "one" | "sub"
1741          * filter = LDAP search filter
1742          *
1743          * The form of the objectspec is as follows:
1744          * ["nis+:"] colspec  [objectspec]
1745          * objectspec   = objectname | "[" indexlist "]" tablename
1746          * objectname   = The name of a NIS+ object
1747          * tablename    = The name of a NIS+ table
1748          * indexlist    = colspec ["," colspec]
1749          * colspec      = colname "=" colvalue
1750          * colname      = The name of a column in the table
1751          * colvalue     = colvaluestring | \" colvaluestring \"
1752          */
1753 
1754         for (; p_error == no_parse_error; ) {
1755                 while (s < end_s && is_whitespace(*s))
1756                         s++;
1757                 len = end_s - s;
1758                 if (yp2ldap) {
1759                         if ((begin_token = skip_string("ldap:", s,
1760                                 len)) != NULL) {
1761                                 item->type = mit_ldap;
1762                         } else if ((begin_token = skip_string("yp:", s,
1763                                 len)) != NULL) {
1764                                 item->type = mit_nisplus;
1765                         } else {
1766                                 item->type = type;
1767                                 begin_token = s;
1768                         }
1769                 } else {
1770                         if ((begin_token = skip_string("ldap:", s,
1771                                 len)) != NULL) {
1772                         item->type = mit_ldap;
1773                         } else if ((begin_token = skip_string("nis+:", s,
1774                                 len)) != NULL) {
1775                                 item->type = mit_nisplus;
1776                         } else if ((begin_token = skip_string("nisplus:", s,
1777                                 len)) != NULL) {
1778                                 item->type = mit_nisplus;
1779                         } else {
1780                                 item->type = type;
1781                                 begin_token = s;
1782                         }
1783                 }
1784 
1785                 end_token = end_s;
1786                 s = get_next_token(&begin_token, &end_token, &t);
1787                 if (s == NULL || t != string_token) {
1788                         p_error = parse_bad_item_format;
1789                         break;
1790                 }
1791 
1792                 item->name = s_strndup_esc(begin_token,
1793                         end_token - begin_token);
1794                 if (item->name == NULL)
1795                         break;
1796                 if (item->type == mit_ldap) {
1797                         item->searchSpec.triple.scope = LDAP_SCOPE_UNKNOWN;
1798                         begin_token = s;
1799                         end_token = end_s;
1800                         s_sav = s;
1801                         s = get_next_token(&begin_token, &end_token, &t);
1802                         if (s != NULL && t == colon_token) {
1803                                 s = get_search_triple(s, end_s,
1804                                         &item->searchSpec.triple);
1805                                 if (s == NULL)
1806                                         break;
1807                         } else
1808                                 s = s_sav;
1809                 } else if (item->type == mit_nisplus) {
1810                         while (s < end_s && is_whitespace(*s))
1811                                 s++;
1812 
1813                         if (s < end_s && *s == OPEN_BRACKET) {
1814                                 index_string = getIndex(&s, end_s);
1815                                 if (index_string == NULL)
1816                                         break;
1817                                 (void) parse_index(index_string,
1818                                         index_string + strlen(index_string),
1819                                         &item->searchSpec.obj.index);
1820                                 free(index_string);
1821                                 if (p_error != no_parse_error)
1822                                         break;
1823                         }
1824                         s_sav = s;
1825                         begin_token = s;
1826                         end_token = end_s;
1827                         s = get_next_token(&begin_token, &end_token, &t);
1828                         if (s != NULL && t == string_token) {
1829                                 name = s_strndup_esc(begin_token,
1830                                         end_token - begin_token);
1831                                 if (name == NULL)
1832                                         break;
1833                                 item->searchSpec.obj.name = name;
1834                         } else
1835                                 s = s_sav;
1836                 }
1837                 if (p_error == no_parse_error)
1838                         return (s);
1839         }
1840         free_mapping_item(item);
1841         (void) memset(item, 0, sizeof (*item));
1842         if (name == NULL)
1843                 free(name);
1844         return (NULL);
1845 }
1846 
1847 static const char *
1848 get_print_sub_element(const char                *s,
1849                 const char                      *end_s,
1850                 __nis_mapping_item_type_t       type,
1851                 __nis_mapping_sub_element_t     *sub)
1852 {
1853 
1854         int                     k;
1855         int                     n;
1856         const char              *begin_token;
1857         const char              *end_token;
1858         token_type              t;
1859         __nis_mapping_format_t  *base;
1860         __nis_mapping_item_t    *print_item;
1861 
1862         k = 0;
1863         base = sub->element.print.fmt;
1864         print_item = sub->element.print.item;
1865         sub->element.print.doElide = FALSE;
1866         sub->element.print.elide = '\0';
1867 
1868         for (n = 0; base[n].type != mmt_end; n++) {
1869                 if (base[n].type != mmt_item && base[n].type != mmt_berstring) {
1870                         if (base[n].type == mmt_berstring_null)
1871                                         base[n].type = mmt_berstring;
1872                         continue;
1873                 }
1874                 s = skip_token(s, end_s, comma_token);
1875                 if (s == NULL) {
1876                         p_error = parse_bad_print_format;
1877                         break;
1878                 }
1879 
1880                 begin_token = s;
1881                 end_token = end_s;
1882                 s = get_next_token(&begin_token, &end_token, &t);
1883                 if (s == NULL)
1884                         break;
1885                 /*
1886                  * Determine if of the form
1887                  * ("fmt", (item), "delim") or
1888                  * ("fmt", item1, item2, ..., item n)
1889                  */
1890                 if (t == open_paren_token) {
1891                         if (sub->element.print.numItems != 1) {
1892                                 p_error = parse_invalid_print_arg;
1893                                 break;
1894                         }
1895                         s = get_mapping_item(s, end_s, &print_item[k++], type);
1896                         s = skip_token(s, end_s, close_paren_token);
1897                         s = skip_token(s, end_s, comma_token);
1898                         if (s == NULL) {
1899                                 p_error = parse_bad_print_format;
1900                                 break;
1901                         }
1902                         begin_token = s;
1903                         end_token = end_s;
1904                         s = get_next_token(&begin_token, &end_token, &t);
1905                         if (s == NULL)
1906                                 break;
1907                         if (t != quoted_string_token ||
1908                                     begin_token + 1 != end_token) {
1909                                 p_error = parse_bad_elide_char;
1910                                 break;
1911                         }
1912                         sub->element.print.elide = *begin_token;
1913                         sub->element.print.doElide = TRUE;
1914                         print_item[0].repeat = TRUE;
1915                         break;
1916                 }
1917                 s = get_mapping_item(begin_token, end_s,
1918                         &print_item[k++], type);
1919                 if (s == NULL)
1920                         break;
1921 
1922                 if (p_error != no_parse_error)
1923                         break;
1924         }
1925 
1926         return (p_error == no_parse_error ? s : NULL);
1927 }
1928 
1929 /*
1930  * FUNCTION:    get_subElement
1931  *
1932  *      Parse attribute string to get sub element item
1933  *
1934  * RETURN VALUE:        NULL if error
1935  *                      position of beginning next token after item
1936  *
1937  * INPUT:               the attribute value and mapping rule type
1938  */
1939 
1940 static const char *
1941 get_subElement(
1942         const char                      *s,
1943         const char                      *end_s,
1944         __nis_mapping_sub_element_t     *subelement,
1945         __nis_mapping_item_type_t       type)
1946 {
1947         token_type                      t;
1948         const char                      *begin_token;
1949         const char                      *end_token;
1950         char                            *fmt_string;
1951         __nis_mapping_item_t            item;
1952         __nis_mapping_element_type_t    e_type;
1953         __nis_mapping_item_t            *print_item     = NULL;
1954         __nis_mapping_format_t          *base           = NULL;
1955         int                             n               = 0;
1956         int                             numItems        = 0;
1957         unsigned char                   delim;
1958         __nis_mapping_sub_element_t     sub;
1959 
1960 /*
1961  *      What is the form of we are expecting here
1962  *      item                                    me_item
1963  *      (item)                                  me_item
1964  *      ("fmt", item1, item2, ..., item n)      me_print
1965  *      ("fmt", (item), "elide")                me_print
1966  *      (name, "delim")                         me_split
1967  *      (item, "fmt")                           me_extract
1968  */
1969         (void) memset(&item, 0, sizeof (item));
1970 
1971         for (; p_error == no_parse_error; ) {
1972                 begin_token = s;
1973                 end_token = end_s;
1974                 s = get_next_token(&begin_token, &end_token, &t);
1975                 if (s == NULL)
1976                         break;
1977                 if (t == string_token) {        /* me_item */
1978                         s = get_mapping_item(begin_token, end_s,
1979                                 &subelement->element.item, type);
1980                         if (s == NULL)
1981                                 break;
1982                         subelement->type = me_item;
1983                         return (s);
1984                 } else if (t != open_paren_token) {
1985                         p_error = parse_item_expected_error;
1986                         break;
1987                 }
1988 
1989                 begin_token = s;
1990                 end_token = end_s;
1991                 s = get_next_token(&begin_token, &end_token, &t);
1992                 if (s == NULL)
1993                         break;
1994 
1995                 if (t != string_token && t != quoted_string_token) {
1996                         p_error = parse_item_expected_error;
1997                         break;
1998                 }
1999                 e_type = me_print;
2000                 if (t == string_token) {
2001                         /* me_item, me_extract or me_split */
2002                         s = get_mapping_item(begin_token, end_s, &item, type);
2003                         if (s == NULL)
2004                                 break;
2005 
2006                         begin_token = s;
2007                         end_token = end_s;
2008                         s = get_next_token(&begin_token, &end_token, &t);
2009                         if (s == NULL) {
2010                                 p_error = parse_unexpected_data_end_rule;
2011                                 break;
2012                         } else if (t == close_paren_token) {
2013                                 subelement->type = me_item;
2014                                 item.repeat = TRUE;
2015                                 subelement->element.item = item;
2016                                 if (yp2ldap) {
2017                                         while (s < end_s && is_whitespace(*s))
2018                                                 s++;
2019                                         if (s == end_s) {
2020                                                 p_error =
2021                                                 parse_unexpected_data_end_rule;
2022                                                 break;
2023                                         }
2024                                         if (*s == DASH_CHAR && s < end_s) {
2025                                                 s++;
2026                                                 while (s < end_s &&
2027                                                         is_whitespace(*s))
2028                                                         s++;
2029                                                 begin_token = s;
2030                                                 end_token = end_s;
2031 
2032                                                 subelement->element.item.exItem
2033                                                         =
2034                                                         (__nis_mapping_item_t *)
2035                                         s_malloc(sizeof (__nis_mapping_item_t));
2036                                                 if (!subelement->
2037                                                 element.item.exItem)
2038                                                         break;
2039                                                 s = get_mapping_item(s, end_s,
2040                                                         subelement->
2041                                                         element.item.exItem,
2042                                                         type);
2043                                                 if (s == NULL) {
2044                                                         p_error =
2045                                                         parse_internal_error;
2046                                                         free_mapping_item(
2047                                                         subelement->
2048                                                         element.item.exItem);
2049                                                         subelement->
2050                                                         element.item.exItem =
2051                                                                 NULL;
2052                                                         break;
2053                                                 }
2054                                         }
2055                                 }
2056                                 return (s);
2057                         } else if (t != comma_token) {
2058                                 p_error = parse_comma_expected_error;
2059                                 break;
2060                         }
2061 
2062                         begin_token = s;
2063                         end_token = end_s;
2064                         s = get_next_token(&begin_token, &end_token, &t);
2065                         if (s == NULL || t != quoted_string_token) {
2066                                 p_error = parse_format_string_expected_error;
2067                                 break;
2068                         }
2069                         if (end_token == begin_token + 1 ||
2070                             *begin_token == ESCAPE_CHAR &&
2071                             end_token == begin_token + 2) {
2072                                         /* me_split */
2073                                 delim = (unsigned char)end_token[-1];
2074                                 s = skip_token(s, end_s, close_paren_token);
2075                                 if (s == NULL)
2076                                         break;
2077                                 subelement->element.split.item = item;
2078                                 subelement->element.split.delim = delim;
2079                                 subelement->type = me_split;
2080                                 return (s);
2081                         }
2082                         e_type = me_extract;
2083                 }
2084                 fmt_string = s_strndup(begin_token, end_token - begin_token);
2085                 if (fmt_string == NULL)
2086                         break;
2087                 if (!get_mapping_format(fmt_string, &base, &n, &numItems,
2088                     e_type == me_print)) {
2089                         free(fmt_string);
2090                         break;
2091                 }
2092                 free(fmt_string);
2093 
2094                 if (numItems != 1 && e_type == me_extract) {
2095                         p_error = numItems == 0 ?
2096                                 parse_not_enough_extract_items :
2097                                 parse_too_many_extract_items;
2098                         break;
2099                 } else if (numItems > 0 && e_type == me_print) {
2100                         print_item = (__nis_mapping_item_t *)s_calloc(numItems,
2101                                 sizeof (__nis_mapping_item_t));
2102                         if (print_item == NULL)
2103                                 break;
2104                 }
2105 
2106                 if (e_type == me_print) {
2107                         sub.element.print.numItems = numItems;
2108                         sub.element.print.fmt = base;
2109                         sub.element.print.item = print_item;
2110                         s = get_print_sub_element(s, end_s, type, &sub);
2111                         if (s == NULL)
2112                                 break;
2113                 }
2114                 s = skip_token(s, end_s, close_paren_token);
2115                 if (s == NULL)
2116                         break;
2117 
2118                 subelement->type = e_type;
2119                 if (e_type == me_extract) {
2120                         subelement->element.extract.fmt = base;
2121                         subelement->element.extract.item = item;
2122                 } else {
2123                         subelement->type = me_print;
2124                         subelement->element.print.fmt = base;
2125                         subelement->element.print.numItems = numItems;
2126                         subelement->element.print.item = print_item;
2127                         subelement->element.print.doElide =
2128                                 sub.element.print.doElide;
2129                         subelement->element.print.elide =
2130                                 sub.element.print.elide;
2131                 }
2132                 if (p_error == no_parse_error)
2133                         return (s);
2134         }
2135         free_mapping_item(&item);
2136         if (base != NULL)
2137                 free_mapping_format(base);
2138         if (print_item) {
2139                 for (n = 0; n < numItems; n++)
2140                         free_mapping_item(&print_item[n]);
2141                 free(print_item);
2142         }
2143 
2144         return (NULL);
2145 }
2146 
2147 /*
2148  * FUNCTION:    skip_get_dn
2149  *
2150  *      Get first token after dn
2151  *
2152  * RETURN VALUE:        NULL if error (not valid dn)
2153  *                      position of beginning next token after dn
2154  *
2155  * INPUT:               the attribute value
2156  */
2157 
2158 const char *
2159 skip_get_dn(const char *dn, const char *end)
2160 {
2161         size_t          len             = 0;
2162         bool_t          in_quote        = FALSE;
2163         bool_t          goteq           = FALSE;
2164         bool_t          gotch           = FALSE;
2165         bool_t          done            = FALSE;
2166         bool_t          last_comma      = FALSE;
2167         const char      *last_dn        = dn;
2168 
2169         while (!done) {
2170                 dn += len;
2171                 if (last_comma) {
2172                         last_dn = dn;
2173                         last_comma = FALSE;
2174                 }
2175                 if (dn >= end)
2176                         break;
2177                 len = 1;
2178                 switch (*dn) {
2179                         case ESCAPE_CHAR:
2180                                 len = 2;
2181                                 gotch = TRUE;
2182                                 break;
2183                         case DOUBLE_QUOTE_CHAR:
2184                                 in_quote = !in_quote;
2185                                 break;
2186                         case QUESTION_MARK:
2187                         case CLOSE_PAREN_CHAR:
2188                         case COLON_CHAR:
2189                                 done = !in_quote;
2190                                 /* FALLTHRU */
2191                         case SEMI_COLON_CHAR:
2192                         case PLUS_SIGN:
2193                         case COMMA_CHAR:
2194                                 if (!in_quote) {
2195                                         if (!goteq || !gotch)
2196                                                 return (last_dn);
2197                                         goteq = FALSE;
2198                                         gotch = FALSE;
2199                                         if (*dn != PLUS_SIGN)
2200                                                 last_dn = dn;
2201                                         last_comma = *dn == COMMA_CHAR;
2202                                 } else {
2203                                         gotch = TRUE;
2204                                 }
2205                                 break;
2206                         case EQUAL_CHAR:
2207                                 if (!in_quote) {
2208                                         if (!gotch || goteq)
2209                                                 return (NULL);
2210                                         goteq = TRUE;
2211                                         gotch = FALSE;
2212                                 } else {
2213                                         gotch = TRUE;
2214                                 }
2215                                 break;
2216                         default:
2217                                 if (!is_whitespace(*dn))
2218                                         gotch = TRUE;
2219                                 break;
2220                 }
2221         }
2222 
2223         if (dn == end) {
2224                 if (!in_quote && goteq && gotch)
2225                         last_dn = dn;
2226         }
2227 
2228         return (last_dn);
2229 }
2230 
2231 /*
2232  * FUNCTION:    get_ldap_filter_element
2233  *
2234  *      Get an ldap filter element for a given string
2235  *
2236  * RETURN VALUE:        NULL if error
2237  *                      __nis_mapping_element_t if success
2238  *
2239  * INPUT:               the string to parse
2240  */
2241 
2242 static __nis_mapping_element_t *
2243 get_ldap_filter_element(
2244         const char                      *s,
2245         const char                      *end_s
2246 )
2247 {
2248         token_type                      t;
2249         const char                      *begin_token;
2250         const char                      *end_token;
2251         char                            *format_str;
2252         __nis_mapping_element_t         *e              = NULL;
2253 
2254         begin_token = s;
2255         end_token = end_s;
2256         s = get_next_token(&begin_token, &end_token, &t);
2257         if (s == NULL || t != open_paren_token)
2258                 return (NULL);
2259 
2260         begin_token = s;
2261         end_token = end_s;
2262         s = get_next_token(&begin_token, &end_token, &t);
2263         if (s == NULL || t != quoted_string_token)
2264                 return (NULL);
2265 
2266         format_str = s_strndup(begin_token, end_token - begin_token);
2267         if (format_str == NULL)
2268                 return (NULL);
2269         e = (__nis_mapping_element_t *)
2270                 s_calloc(1, sizeof (__nis_mapping_element_t));
2271         if (e != NULL) {
2272                 (void) get_print_mapping_element(s, end_s,
2273                                 format_str, e, mit_nisplus);
2274                 if (p_error != no_parse_error) {
2275                         free_mapping_element(e);
2276                         e = NULL;
2277                 }
2278         }
2279         free(format_str);
2280         return (e);
2281 }
2282 
2283 /*
2284  * FUNCTION:    get_search_triple
2285  *
2286  *      Get the search triple or if NULL determine if valid
2287  *
2288  * RETURN VALUE:        NULL if error
2289  *                      position of beginning next token after
2290  *                      search triple
2291  *
2292  * INPUT:               the attribute value
2293  */
2294 
2295 const char *
2296 get_search_triple(
2297         const char                      *s,
2298         const char                      *end_s,
2299         __nis_search_triple_t           *triple
2300 )
2301 {
2302         const char      *begin_token;
2303         const char      *end_token;
2304         char            *search_base    = NULL;
2305         int             scope           = LDAP_SCOPE_ONELEVEL;
2306         char            *filter         = NULL;
2307         const char      *s1;
2308         __nis_mapping_element_t
2309                         *element        = NULL;
2310 
2311         /*
2312          * The form of the searchTriple is assumed to be as follows:
2313          * searchTriple = [baseDN] ["?" [scope] ["?" [filter]]]
2314          * baseDN = Base DN for search
2315          * scope = "base" | "one" | "sub"
2316          * filter = LDAP search filter
2317          */
2318         for (; p_error == no_parse_error; ) {
2319                 while (s < end_s && is_whitespace(*s))
2320                         s++;
2321                 if (s == end_s)
2322                         break;
2323 
2324                 if (!IS_TERMINAL_CHAR(*s)) {
2325                         begin_token = s;
2326                         s = skip_get_dn(begin_token, end_s);
2327                         if (s == NULL) {
2328                                 p_error = parse_invalid_dn;
2329                                 break;
2330                         }
2331                         if (triple != NULL) {
2332                                 search_base = s_strndup(begin_token,
2333                                         s - begin_token);
2334                                 if (search_base == NULL)
2335                                         break;
2336                         }
2337                         while (s < end_s && is_whitespace(*s))
2338                                 s++;
2339                         if (s == end_s)
2340                                 break;
2341                 }
2342 
2343                 if (!IS_TERMINAL_CHAR(*s)) {
2344                         p_error = parse_bad_ldap_item_format;
2345                         break;
2346                 }
2347                 if (*s != QUESTION_MARK)
2348                         break;
2349 
2350                 s++;
2351                 while (s < end_s && is_whitespace(*s))
2352                         s++;
2353                 if (s == end_s)
2354                         break;
2355 
2356                 /* base, one, or sub, or empty value */
2357                 if (!IS_TERMINAL_CHAR(*s)) {
2358                         if ((s1 = skip_string("base", s, end_s - s)) != NULL) {
2359                                 scope = LDAP_SCOPE_BASE;
2360                         } else if ((s1 = skip_string("one", s, end_s - s)) !=
2361                                         NULL) {
2362                                 scope = LDAP_SCOPE_ONELEVEL;
2363                         } else if ((s1 = skip_string("sub", s, end_s - s)) !=
2364                                         NULL) {
2365                                 scope = LDAP_SCOPE_SUBTREE;
2366                         } else if (s + 1 < end_s && *s != QUESTION_MARK) {
2367                                 p_error = parse_invalid_scope;
2368                                 break;
2369                         }
2370                         if (s1 != NULL)
2371                                 s = s1;
2372                         while (s < end_s && is_whitespace(*s))
2373                                 s++;
2374                 }
2375 
2376                 if (s == end_s)
2377                         break;
2378                 if (*s != QUESTION_MARK)
2379                         break;
2380                 s++;
2381                 while (s < end_s && is_whitespace(*s))
2382                         s++;
2383                 if (s == end_s || IS_TERMINAL_CHAR(*s))
2384                         break;
2385 
2386                 /* LDAP search filter */
2387                 if (*s == OPEN_PAREN_CHAR) {
2388                     begin_token = s;
2389                     end_token = end_s;
2390                     s = get_ldap_filter(&begin_token, &end_token);
2391                     if (s == NULL)
2392                         break;
2393                     s = end_token;
2394                     element = get_ldap_filter_element(begin_token, end_token);
2395                     if (element != NULL)
2396                         break;
2397                 } else {
2398                     begin_token = s;
2399                     end_token = end_s;
2400                     s = get_ava_list(&begin_token, &end_token, TRUE);
2401                     if (s == NULL)
2402                         break;
2403                     s = end_token;
2404                 }
2405                 if (triple != NULL)
2406                         filter = s_strndup(begin_token, s - begin_token);
2407                 if (p_error == no_parse_error)
2408                         break;
2409         }
2410         if (p_error == no_parse_error && triple != NULL) {
2411                 triple->base = search_base;
2412                 triple->scope = scope;
2413                 triple->attrs = filter;
2414                 triple->element = element;
2415                 element = NULL;
2416                 filter = NULL;
2417                 search_base = NULL;
2418         }
2419 
2420         if (search_base != NULL)
2421                 free(search_base);
2422         if (filter != NULL)
2423                 free(filter);
2424         if (element != NULL) {
2425                 free_mapping_element(element);
2426                 free(element);
2427         }
2428         return (p_error == no_parse_error ? s : NULL);
2429 }
2430 
2431 /*
2432  * FUNCTION:    get_mapping_format
2433  *
2434  *      Get the __nis_mapping_format_t from the string
2435  *
2436  * RETURN VALUE:        FALSE if error
2437  *                      TRUE if __nis_mapping_format_t returned
2438  *
2439  * INPUT:               the format string
2440  */
2441 
2442 static bool_t
2443 get_mapping_format(
2444         const char              *fmt_string,
2445         __nis_mapping_format_t  **fmt,
2446         int                     *nfmt,
2447         int                     *numItems,
2448         bool_t                  print_mapping)
2449 {
2450         const char              *f      = fmt_string;
2451         const char              *ef;
2452         __nis_mapping_format_t  *b;
2453         __nis_mapping_format_t  *base   = NULL;
2454         int                     n       = 0;
2455         int                     nItems  = 0;
2456 
2457         f = fmt_string;
2458         ef = f + strlen(f);
2459         base = (__nis_mapping_format_t *)
2460             s_calloc(1, sizeof (__nis_mapping_format_t));
2461 
2462         if (base == NULL)
2463                 return (FALSE);
2464         base->type = mmt_begin;
2465         n++;
2466 
2467         for (;;) {
2468                 b = (__nis_mapping_format_t *)s_realloc(
2469                     base, (n + 1) * sizeof (__nis_mapping_format_t));
2470 
2471                 if (b == NULL)
2472                         break;
2473                 base = b;
2474                 base[n].type = mmt_end;
2475                 if (f == ef) {
2476                         if (nfmt)
2477                                 *nfmt = n + 1;
2478                         *fmt = base;
2479                         if (numItems)
2480                                 *numItems = nItems;
2481                         return (TRUE);
2482                 }
2483                 if (print_mapping)
2484                     f = get_next_print_format_item(f, ef, &base[n]);
2485                 else
2486                     f = get_next_extract_format_item(f, ef, &base[n]);
2487 
2488 
2489                 if (f == NULL)
2490                         break;
2491                 if (base[n].type == mmt_item ||
2492                         base[n].type == mmt_berstring)
2493                         nItems++;
2494                 n++;
2495         }
2496         if (base != NULL)
2497                 free_mapping_format(base);
2498         return (FALSE);
2499 }
2500 
2501 /*
2502  * FUNCTION:    getIndex
2503  *
2504  *      Returns a string containing the index
2505  *
2506  * RETURN VALUE:        NULL if error
2507  *                      a string containing the index
2508  *
2509  * INPUT:               attribute containing the index
2510  */
2511 
2512 static char *
2513 getIndex(const char **s_cur, const char *s_end)
2514 {
2515         const char      *s              = *s_cur + 1;
2516         const char      *s1;
2517         char            *s_index;
2518         char            *s_index1;
2519         char            *s_index_end;
2520         int             n_brackets      = 1;
2521         bool_t          in_quotes       = FALSE;
2522         char            *index          = NULL;
2523 
2524         while (s < s_end && is_whitespace(*s))
2525                 s++;
2526         for (s1 = s; s1 < s_end; s1++) {
2527                 if (*s1 == ESCAPE_CHAR)
2528                         s1++;
2529                 else if (*s1 == DOUBLE_QUOTE_CHAR) {
2530                         in_quotes = !in_quotes;
2531                 } else if (in_quotes)
2532                         ;
2533                 else if (*s1 == CLOSE_BRACKET) {
2534                         if (--n_brackets == 0)
2535                                 break;
2536                 } else if (*s1 == OPEN_BRACKET)
2537                         n_brackets++;
2538         }
2539 
2540         if (n_brackets == 0) {
2541                 index = s_strndup(s, s1 - s);
2542                 if (index != NULL) {
2543                         s_index_end = index + (s1 - s);
2544                         s_index1 = index;
2545                         for (s_index = index; s_index < s_index_end;
2546                             s_index++) {
2547                                 if (*s_index == ESCAPE_CHAR) {
2548                                         *s_index1++ = *s_index++;
2549                                 } else if (*s_index == DOUBLE_QUOTE_CHAR) {
2550                                         in_quotes = !in_quotes;
2551                                 } else if (!in_quotes &&
2552                                     is_whitespace(*s_index)) {
2553                                         continue;
2554                                 }
2555                                 *s_index1++ = *s_index;
2556                         }
2557                         *s_index1 = *s_index;
2558 
2559                         s = s1 + 1;
2560 
2561                         while (s < s_end && is_whitespace(*s))
2562                                 s++;
2563                         *s_cur = s;
2564                 }
2565         } else
2566                 p_error = parse_mismatched_brackets;
2567 
2568         return (index);
2569 }
2570 
2571 /*
2572  * FUNCTION:    parse_index
2573  *
2574  *      Parse attribute string to get __nis_index_t
2575  *
2576  * RETURN VALUE:        FALSE if error
2577  *                      TRUE if __nis_index_t returned
2578  *
2579  * INPUT:               the attribute value to parse
2580  */
2581 
2582 bool_t
2583 parse_index(const char *s, const char *end_s, __nis_index_t *index)
2584 {
2585         const char              *begin_token;
2586         const char              *end_token;
2587         char                    *name_str       = NULL;
2588         char                    **name;
2589         char                    *fmt_string     = NULL;
2590         __nis_mapping_format_t  *v              = NULL;
2591         __nis_mapping_format_t  **value;
2592         token_type              t;
2593         int                     n                = 0;
2594 
2595         if (index != NULL)
2596                 (void) memset(index, 0, sizeof (*index));
2597 
2598         while (s < end_s) {
2599                 if (n > 0) {
2600                         s = skip_token(s, end_s, comma_token);
2601                         if (s == NULL) {
2602                                 p_error = parse_bad_index_format;
2603                                 break;
2604                         }
2605                 }
2606                 begin_token = s;
2607                 end_token = end_s;
2608                 s = get_next_token(&begin_token, &end_token, &t);
2609                 if (s == NULL)
2610                         break;
2611                 if (t != string_token) {
2612                         p_error = parse_bad_index_format;
2613                         break;
2614                 }
2615                 s = skip_token(s, end_s, equal_token);
2616                 if (s == NULL) {
2617                         p_error = parse_bad_index_format;
2618                         break;
2619                 }
2620                 if (index != NULL) {
2621                         name_str = s_strndup_esc(begin_token,
2622                                 end_token - begin_token);
2623                         if (name_str == NULL)
2624                                 break;
2625                 }
2626                 begin_token = s;
2627                 end_token = end_s;
2628                 s = get_next_token(&begin_token, &end_token, &t);
2629                 if (s == NULL)
2630                         break;
2631                 if (t != string_token && t != quoted_string_token) {
2632                         p_error = parse_bad_index_format;
2633                         break;
2634                 }
2635                 fmt_string = s_strndup(begin_token, end_token - begin_token);
2636                 if (fmt_string == NULL)
2637                         break;
2638                 if (!get_mapping_format(fmt_string, &v, NULL, NULL, FALSE))
2639                         break;
2640                 free(fmt_string);
2641                 fmt_string = NULL;
2642                 if (index != NULL) {
2643                         name = s_realloc(index->name,
2644                                 (n + 1) * sizeof (char *));
2645                         if (name == NULL)
2646                                 break;
2647                         value = s_realloc(index->value,
2648                                 (n + 1) * sizeof (__nis_mapping_format_t *));
2649                         if (value == NULL)
2650                                 break;
2651                         name[n] = name_str;
2652                         name_str = NULL;
2653                         value[n] = v;
2654                         v = NULL;
2655                         index->numIndexes = ++n;
2656                         index->name = name;
2657                         index->value = value;
2658                 } else if (v != NULL) {
2659                         free_mapping_format(v);
2660                         v = NULL;
2661                 }
2662         }
2663         if (p_error != no_parse_error) {
2664                 if (name_str != NULL)
2665                         free(name_str);
2666                 if (v != NULL)
2667                         free_mapping_format(v);
2668                 if (fmt_string != NULL)
2669                         free(fmt_string);
2670                 if (index != NULL)
2671                         free_index(index);
2672         }
2673         return (p_error != no_parse_error);
2674 }
2675 
2676 /*
2677  * FUNCTION:    get_deleteDisp
2678  *
2679  *      Parse deleteDisp. Sets p_error if an error occurred.
2680  *
2681  * RETURN VALUE:        TRUE on success
2682  *                      FAILURE on failure
2683  *
2684  * INPUT:               begin and end of string and __nis_object_dn_t
2685  */
2686 
2687 static bool_t
2688 get_deleteDisp(const char *s_begin, const char *s_end,
2689                 __nis_object_dn_t *obj_dn)
2690 {
2691         /*
2692          * deleteDisp: "always" | perDbId | "never"
2693          * perDbId: "dbid" "=" delDatabaseId
2694          */
2695 
2696         if (same_string("always", s_begin, s_end - s_begin)) {
2697                 obj_dn->delDisp = dd_always;
2698         } else if (same_string("never", s_begin, s_end - s_begin)) {
2699                 obj_dn->delDisp = dd_never;
2700         } else if ((s_begin = skip_string("dbid", s_begin, s_end - s_begin))
2701                         != NULL) {
2702                 obj_dn->delDisp = dd_perDbId;
2703                 while (s_begin < s_end && is_whitespace(*s_begin))
2704                         s_begin++;
2705                 if (s_begin == s_end || *s_begin != EQUAL_CHAR) {
2706                         p_error = parse_object_dn_syntax_error;
2707                 } else {
2708                         s_begin++;
2709                         while (s_begin < s_end && is_whitespace(*s_begin))
2710                                 s_begin++;
2711                         while (s_begin < s_end && is_whitespace(s_end[-1]))
2712                                 s_end--;
2713                         if (s_begin == s_end) {
2714                                 p_error = parse_object_dn_syntax_error;
2715                         } else {
2716                                 obj_dn->dbIdName =
2717                                         s_strndup(s_begin, s_end - s_begin);
2718                         }
2719                 }
2720         } else {
2721                 p_error = parse_object_dn_syntax_error;
2722         }
2723         return (p_error == no_parse_error);
2724 }