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 2004 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 <errno.h>
  36 #include <locale.h>
  37 #include <lber.h>
  38 #include <ldap.h>
  39 #include <syslog.h>
  40 #include <dlfcn.h>        /* for dynamic loading only */
  41 
  42 #include "ldap_parse.h"
  43 #include "nis_parse_ldap_conf.h"
  44 #include "nis_parse_ldap_err.h"
  45 #include "ldap_util.h"
  46 #include "ldap_util.h"
  47 
  48 void append_dot(char **str);
  49 void    append_comma(char **str);
  50 bool_t make_full_dn(char **dn, const char *base);
  51 bool_t make_fqdn(__nis_object_dn_t *dn, const char *base);
  52 char *get_default_ldap_base(const char *domain);
  53 bool_t add_domain(char **objName, const char *domain);
  54 bool_t add_column(__nis_table_mapping_t *t, const char *col_name);
  55 __nis_mapping_rule_t **dup_mapping_rules(
  56         __nis_mapping_rule_t **rules, int n_rules);
  57 __nis_mapping_rule_t *dup_mapping_rule(
  58         __nis_mapping_rule_t *in);
  59 void *s_malloc(size_t size);
  60 __nis_mapping_format_t *dup_format_mapping(
  61         __nis_mapping_format_t *in);
  62 bool_t dup_mapping_element(__nis_mapping_element_t *in,
  63         __nis_mapping_element_t *out);
  64 
  65 extern FILE *cons;
  66 
  67 /*
  68  * FUNCTION:    free_parse_structs
  69  *
  70  *      Release the resources in parse results
  71  *
  72  */
  73 
  74 void
  75 free_parse_structs()
  76 {
  77         __nis_table_mapping_t   *t;
  78         __nis_table_mapping_t   *t1;
  79 
  80         free_proxy_info(&proxyInfo);
  81         for (t = ldapTableMapping; t != NULL; t = t1) {
  82                 t1 = t->next;
  83                 free_table_mapping(t);
  84         }
  85         ldapTableMapping = NULL;
  86 }
  87 
  88 /*
  89  * FUNCTION:    initialize_parse_structs
  90  *
  91  *      Initialize fields to unset values
  92  *
  93  * INPUT:               __nis_ldap_proxy_info, __nis_config_t
  94  *                      and __nisdb_table_mapping_t structures
  95  */
  96 
  97 void
  98 initialize_parse_structs(
  99         __nis_ldap_proxy_info   *proxy_info,
 100         __nis_config_t          *config_info,
 101         __nisdb_table_mapping_t *table_info)
 102 {
 103         proxy_info->default_servers = NULL;
 104         proxy_info->auth_method = (auth_method_t)NO_VALUE_SET;
 105         proxy_info->tls_method = (tls_method_t)NO_VALUE_SET;
 106         proxy_info->tls_cert_db = NULL;
 107         proxy_info->default_search_base = NULL;
 108         proxy_info->proxy_dn = NULL;
 109         proxy_info->proxy_passwd = NULL;
 110         proxy_info->default_nis_domain = NULL;
 111         proxy_info->bind_timeout.tv_sec = (time_t)NO_VALUE_SET;
 112         proxy_info->bind_timeout.tv_usec = 0;
 113         proxy_info->search_timeout.tv_sec = (time_t)NO_VALUE_SET;
 114         proxy_info->search_timeout.tv_usec = 0;
 115         proxy_info->modify_timeout.tv_sec = (time_t)NO_VALUE_SET;
 116         proxy_info->modify_timeout.tv_usec = 0;
 117         proxy_info->add_timeout.tv_sec = (time_t)NO_VALUE_SET;
 118         proxy_info->add_timeout.tv_usec = 0;
 119         proxy_info->delete_timeout.tv_sec = (time_t)NO_VALUE_SET;
 120         proxy_info->delete_timeout.tv_usec = 0;
 121         proxy_info->search_time_limit = (int)NO_VALUE_SET;
 122         proxy_info->search_size_limit = (int)NO_VALUE_SET;
 123         proxy_info->follow_referral = (follow_referral_t)NO_VALUE_SET;
 124 
 125 
 126         config_info->initialUpdate = (__nis_initial_update_t)NO_VALUE_SET;
 127         config_info->threadCreationError =
 128                 (__nis_thread_creation_error_t)NO_VALUE_SET;
 129         config_info->threadCreationErrorTimeout.attempts = NO_VALUE_SET;
 130         config_info->threadCreationErrorTimeout.timeout = (time_t)NO_VALUE_SET;
 131         config_info->dumpError = (__nis_dump_error_t)NO_VALUE_SET;
 132         config_info->dumpErrorTimeout.attempts = NO_VALUE_SET;
 133         config_info->dumpErrorTimeout.timeout = (time_t)NO_VALUE_SET;
 134         config_info->resyncService = (__nis_resync_service_t)NO_VALUE_SET;
 135         config_info->updateBatching = (__nis_update_batching_t)NO_VALUE_SET;
 136         config_info->updateBatchingTimeout.timeout = (time_t)NO_VALUE_SET;
 137         config_info->numberOfServiceThreads = (int)NO_VALUE_SET;
 138         config_info->emulate_yp = (int)NO_VALUE_SET;
 139         config_info->maxRPCRecordSize = (int)NO_VALUE_SET;
 140 
 141         table_info->retrieveError = (__nis_retrieve_error_t)NO_VALUE_SET;
 142         table_info->retrieveErrorRetry.attempts = NO_VALUE_SET;
 143         table_info->retrieveErrorRetry.timeout = (time_t)NO_VALUE_SET;
 144         table_info->storeError = (__nis_store_error_t)NO_VALUE_SET;
 145         table_info->storeErrorRetry.attempts = NO_VALUE_SET;
 146         table_info->storeErrorRetry.timeout = (time_t)NO_VALUE_SET;
 147         table_info->refreshError = (__nis_refresh_error_t)NO_VALUE_SET;
 148         table_info->refreshErrorRetry.attempts = NO_VALUE_SET;
 149         table_info->refreshErrorRetry.timeout = (time_t)NO_VALUE_SET;
 150         table_info->matchFetch = (__nis_match_fetch_t)NO_VALUE_SET;
 151 }
 152 
 153 /*
 154  * FUNCTION:    free_mapping_rule
 155  *
 156  *      Frees __nis_mapping_rule_t
 157  *
 158  * INPUT:               __nis_mapping_rule_t
 159  */
 160 
 161 void
 162 free_mapping_rule(__nis_mapping_rule_t  *rule)
 163 {
 164         int                     i;
 165         __nis_mapping_rlhs_t    *r;
 166 
 167         if (rule != NULL) {
 168                 r = &rule->lhs;
 169                 for (i = 0; i < r->numElements; i++)
 170                         free_mapping_element(&r->element[i]);
 171                 if (r->element != NULL)
 172                         free(r->element);
 173 
 174                 r = &rule->rhs;
 175                 for (i = 0; i < r->numElements; i++)
 176                         free_mapping_element(&r->element[i]);
 177                 if (r->element != NULL)
 178                         free(r->element);
 179 
 180                 free(rule);
 181         }
 182 }
 183 
 184 /*
 185  * FUNCTION:    free_mapping_element
 186  *
 187  *      Frees __nis_mapping_element_t
 188  *
 189  * INPUT:               __nis_mapping_element_t
 190  */
 191 
 192 void
 193 free_mapping_element(__nis_mapping_element_t *e)
 194 {
 195         int     i;
 196 
 197         if (e == NULL)
 198                 return;
 199 
 200         switch (e->type) {
 201             case me_item:
 202                 free_mapping_item(&e->element.item);
 203                 break;
 204             case me_print:
 205                 if (e->element.print.fmt != NULL)
 206                         free_mapping_format(e->element.print.fmt);
 207                 e->element.print.fmt = NULL;
 208                 for (i = 0; i < e->element.print.numSubElements; i++)
 209                         free_mapping_sub_element(
 210                                 &e->element.print.subElement[i]);
 211                 e->element.print.numSubElements = 0;
 212                 if (e->element.print.subElement != NULL)
 213                         free(e->element.print.subElement);
 214                 e->element.print.subElement = NULL;
 215                 break;
 216             case me_split:
 217                 free_mapping_item(&e->element.split.item);
 218                 break;
 219             case me_match:
 220                 if (e->element.match.fmt != NULL)
 221                         free_mapping_format(e->element.match.fmt);
 222                 e->element.match.fmt = NULL;
 223                 for (i = 0; i < e->element.match.numItems; i++)
 224                         free_mapping_item(&e->element.match.item[i]);
 225                 e->element.match.numItems = 0;
 226                 if (e->element.match.item != NULL)
 227                     free(e->element.match.item);
 228                 e->element.match.item = NULL;
 229                 break;
 230             case me_extract:
 231                 if (e->element.extract.fmt != NULL)
 232                         free_mapping_format(e->element.extract.fmt);
 233                 e->element.extract.fmt = NULL;
 234                 free_mapping_item(&e->element.extract.item);
 235                 break;
 236         }
 237         e = NULL;
 238 }
 239 
 240 /*
 241  * FUNCTION:    free_table_mapping
 242  *
 243  *      Frees __nis_table_mapping_t
 244  *
 245  * INPUT:               __nis_table_mapping_t
 246  */
 247 
 248 /*
 249  * free_table_mapping does not remove the table mapping from
 250  * its hashed list
 251  */
 252 
 253 void
 254 free_table_mapping(__nis_table_mapping_t *mapping)
 255 {
 256         int     i;
 257 
 258         if (mapping == NULL)
 259                 return;
 260 
 261         if (mapping->dbId != NULL)
 262                 free(mapping->dbId);
 263         mapping->dbId = NULL;
 264 
 265         if (mapping->objName != NULL)
 266                 free(mapping->objName);
 267         mapping->objName = NULL;
 268 
 269         for (i = 0; i < mapping->index.numIndexes; i++) {
 270                 free(mapping->index.name[i]);
 271                 free_mapping_format(mapping->index.value[i]);
 272         }
 273 
 274         if (mapping->index.name != NULL)
 275                 free(mapping->index.name);
 276         mapping->index.name = NULL;
 277 
 278         if (mapping->index.value != NULL)
 279                 free(mapping->index.value);
 280         mapping->index.value = NULL;
 281 
 282         mapping->index.numIndexes = 0;
 283 
 284         if (mapping->column != NULL) {
 285                 for (i = 0; i < mapping->numColumns; i++) {
 286                         free(mapping->column[i]);
 287                 }
 288                 mapping->numColumns = 0;
 289                 free(mapping->column);
 290                 mapping->column = NULL;
 291         }
 292 
 293         if (mapping->commentChar != NULL)
 294                 mapping->commentChar = NULL;
 295 
 296         if (mapping->objectDN != NULL)
 297                 free_object_dn(mapping->objectDN);
 298         mapping->objectDN = NULL;
 299 
 300         if (mapping->separatorStr != NULL)
 301                 mapping->separatorStr = NULL;
 302 
 303         for (i = 0; i < mapping->numRulesFromLDAP; i++) {
 304                 if (mapping->ruleFromLDAP[i]) /* See Comment below */
 305                         free_mapping_rule(mapping->ruleFromLDAP[i]);
 306         }
 307         mapping->numRulesFromLDAP = 0;
 308 
 309         if (mapping->ruleFromLDAP != NULL)
 310                 free(mapping->ruleFromLDAP);
 311         mapping->ruleFromLDAP = NULL;
 312 
 313         for (i = 0; i < mapping->numRulesToLDAP; i++) {
 314                 if (mapping->ruleToLDAP[i])
 315                 /*
 316                  * Normally mapping->ruleToLDAP[i] should
 317                  * always be non-null if
 318                  * mapping->numRulesToLDAP is > 0.
 319                  * However it is possible to have data
 320                  * corruption where numRulesToLDAP gets
 321                  * some integer value even though no real
 322                  * data is present in mapping->ruleToLDAP.
 323                  */
 324                         free_mapping_rule(mapping->ruleToLDAP[i]);
 325         }
 326         mapping->numRulesToLDAP = 0;
 327 
 328         if (mapping->ruleToLDAP != NULL)
 329                 free(mapping->ruleToLDAP);
 330         mapping->ruleToLDAP = NULL;
 331 
 332         if (mapping->e != NULL) {
 333                 /* Similar logic as in above comment applies. */
 334                 for (i = 0; i <= mapping->numSplits; i++) {
 335                         free_mapping_element(&mapping->e[i]);
 336                 }
 337                 free(mapping->e);
 338         }
 339         mapping->e = NULL;
 340 
 341         mapping->numSplits = 0;
 342 
 343         free(mapping);
 344 }
 345 
 346 /*
 347  * FUNCTION:    free_config_info
 348  *
 349  *      Frees __nis_config_info_t
 350  *
 351  * INPUT:               __nis_config_info_t
 352  */
 353 
 354 void
 355 free_config_info(__nis_config_info_t *config_info)
 356 {
 357         if (config_info->config_dn != NULL)
 358                 free(config_info->config_dn);
 359         config_info->config_dn = NULL;
 360 
 361         if (config_info->default_servers != NULL)
 362                 free(config_info->default_servers);
 363         config_info->default_servers = NULL;
 364 
 365         if (config_info->proxy_dn != NULL)
 366                 free(config_info->proxy_dn);
 367         config_info->proxy_dn = NULL;
 368 
 369         if (config_info->proxy_passwd != NULL)
 370                 free(config_info->proxy_passwd);
 371         config_info->proxy_passwd = NULL;
 372 
 373         if (config_info->tls_cert_db != NULL)
 374                 free(config_info->tls_cert_db);
 375         config_info->tls_cert_db = NULL;
 376 }
 377 
 378 /*
 379  * FUNCTION:    free_proxy_info
 380  *
 381  *      Frees __nis_ldap_proxy_info
 382  *
 383  * INPUT:               __nis_ldap_proxy_info
 384  */
 385 
 386 void
 387 free_proxy_info(__nis_ldap_proxy_info *proxy_info)
 388 {
 389         if (proxy_info->tls_cert_db != NULL)
 390                 free(proxy_info->tls_cert_db);
 391         proxy_info->tls_cert_db = NULL;
 392 
 393         if (proxy_info->default_servers != NULL)
 394                 free(proxy_info->default_servers);
 395         proxy_info->default_servers = NULL;
 396 
 397         if (proxy_info->default_search_base != NULL)
 398                 free(proxy_info->default_search_base);
 399         proxy_info->default_search_base = NULL;
 400 
 401         if (proxy_info->proxy_dn != NULL)
 402                 free(proxy_info->proxy_dn);
 403         proxy_info->proxy_dn = NULL;
 404 
 405         if (proxy_info->proxy_passwd != NULL)
 406                 free(proxy_info->proxy_passwd);
 407         proxy_info->proxy_passwd = NULL;
 408 
 409         if (proxy_info->default_nis_domain != NULL)
 410                 free(proxy_info->default_nis_domain);
 411         proxy_info->default_nis_domain = NULL;
 412 }
 413 
 414 /*
 415  * FUNCTION:    free_object_dn
 416  *
 417  *      Frees __nis_object_dn_t
 418  *
 419  * INPUT:               __nis_object_dn_t
 420  */
 421 
 422 void
 423 free_object_dn(__nis_object_dn_t *obj_dn)
 424 {
 425         __nis_object_dn_t       *t;
 426         int                     i;
 427 
 428         while (obj_dn != NULL) {
 429                 if (obj_dn->read.base != NULL)
 430                         free(obj_dn->read.base);
 431                 obj_dn->read.base = NULL;
 432                 if (obj_dn->read.attrs != NULL)
 433                         free(obj_dn->read.attrs);
 434                 obj_dn->read.attrs = NULL;
 435                 if (obj_dn->write.base != NULL)
 436                         free(obj_dn->write.base);
 437                 obj_dn->write.base = NULL;
 438                 if (obj_dn->write.attrs != NULL)
 439                         free(obj_dn->write.attrs);
 440                 obj_dn->write.attrs = NULL;
 441                 if (obj_dn->dbIdName != NULL)
 442                         free(obj_dn->dbIdName);
 443                 obj_dn->dbIdName = NULL;
 444                 for (i = 0; i < obj_dn->numDbIds; i++)
 445                         free_mapping_rule(obj_dn->dbId[i]);
 446                 obj_dn->numDbIds = 0;
 447 
 448                 if (obj_dn->dbId != NULL)
 449                         free(obj_dn->dbId);
 450                 obj_dn->dbId = NULL;
 451 
 452                 t = obj_dn;
 453                 obj_dn = obj_dn->next;
 454                 free(t);
 455         }
 456 }
 457 
 458 /*
 459  * FUNCTION:    free_index
 460  *
 461  *      Frees __nis_index_t
 462  *
 463  * INPUT:               __nis_index_t
 464  */
 465 
 466 void
 467 free_index(__nis_index_t *index)
 468 {
 469         int     i;
 470         for (i = 0; i < index->numIndexes; i++) {
 471                 free(index->name[i]);
 472                 free_mapping_format(index->value[i]);
 473         }
 474         index->numIndexes = 0;
 475         if (index->name != NULL)
 476                 free(index->name);
 477         index->name = NULL;
 478         if (index->value != NULL)
 479                 free(index->value);
 480         index->value = NULL;
 481 }
 482 
 483 /*
 484  * FUNCTION:    free_mapping_item
 485  *
 486  *      Frees __nis_mapping_item_t
 487  *
 488  * INPUT:               __nis_mapping_item_t
 489  */
 490 
 491 void
 492 free_mapping_item(__nis_mapping_item_t  *item)
 493 {
 494         if (item == NULL)
 495                 return;
 496 
 497         if (item->name != NULL)
 498                 free(item->name);
 499         item->name = NULL;
 500         if (item->type == mit_nisplus) {
 501                 free_index(&item->searchSpec.obj.index);
 502                 if (item->searchSpec.obj.name != NULL)
 503                         free(item->searchSpec.obj.name);
 504                 item->searchSpec.obj.name = NULL;
 505         } else if (item->type == mit_ldap) {
 506                 if (item->searchSpec.triple.base != NULL)
 507                         free(item->searchSpec.triple.base);
 508                 item->searchSpec.triple.base = NULL;
 509                 if (item->searchSpec.triple.attrs != NULL)
 510                         free(item->searchSpec.triple.attrs);
 511                 item->searchSpec.triple.attrs = NULL;
 512                 if (item->searchSpec.triple.element != NULL) {
 513                         free_mapping_element(
 514                                 item->searchSpec.triple.element);
 515                         free(item->searchSpec.triple.element);
 516                 }
 517                 item->searchSpec.triple.element = NULL;
 518         }
 519         if (item->exItem != NULL) {
 520                 free_mapping_item(item->exItem);
 521                 free(item->exItem);
 522                 item->exItem = 0;
 523         }
 524 }
 525 
 526 /*
 527  * FUNCTION:    free_mapping_format
 528  *
 529  *      Frees __nis_mapping_format_t
 530  *
 531  * INPUT:               __nis_mapping_format_t
 532  */
 533 
 534 void
 535 free_mapping_format(__nis_mapping_format_t *fmt)
 536 {
 537         __nis_mapping_format_t *f = fmt;
 538 
 539         while (fmt->type != mmt_end) {
 540                 switch (fmt->type) {
 541                     case mmt_item:
 542                         break;
 543                     case mmt_string:
 544                         if (fmt->match.string != NULL)
 545                                 free(fmt->match.string);
 546                         fmt->match.string = NULL;
 547                         break;
 548                     case mmt_single:
 549                         if (fmt->match.single.lo != NULL)
 550                                 free(fmt->match.single.lo);
 551                         fmt->match.single.lo = NULL;
 552                         if (fmt->match.single.hi != NULL)
 553                                 free(fmt->match.single.hi);
 554                         fmt->match.single.hi = NULL;
 555                         break;
 556                     case mmt_limit:
 557                         break;
 558                     case mmt_any:
 559                         break;
 560                     case mmt_berstring:
 561                     case mmt_berstring_null:
 562                         if (fmt->match.berString != NULL)
 563                                 free(fmt->match.berString);
 564                         fmt->match.berString = NULL;
 565                         break;
 566                     case mmt_begin:
 567                         break;
 568                     case mmt_end:
 569                         break;
 570                 }
 571                 fmt++;
 572         }
 573         free(f);
 574 }
 575 
 576 /*
 577  * FUNCTION:    free_mapping_sub_element
 578  *
 579  *      Frees __nis_mapping_sub_element_t
 580  *
 581  * INPUT:               __nis_mapping_sub_element_t
 582  */
 583 
 584 void
 585 free_mapping_sub_element(__nis_mapping_sub_element_t *sub)
 586 {
 587         int     i;
 588 
 589         switch (sub->type) {
 590             case me_item:
 591                 free_mapping_item(&sub->element.item);
 592                 break;
 593             case me_print:
 594                 if (sub->element.print.fmt != NULL)
 595                         free_mapping_format(sub->element.print.fmt);
 596                 sub->element.print.fmt = NULL;
 597                 for (i = 0; i < sub->element.print.numItems; i++)
 598                         free_mapping_item(&sub->element.print.item[i]);
 599                 sub->element.print.numItems = 0;
 600                 if (sub->element.print.item != NULL)
 601                         free(sub->element.print.item);
 602                 sub->element.print.item = NULL;
 603                 break;
 604             case me_split:
 605                 free_mapping_item(&sub->element.split.item);
 606                 break;
 607             case me_extract:
 608                 if (sub->element.extract.fmt != NULL)
 609                         free_mapping_format(sub->element.extract.fmt);
 610                 sub->element.extract.fmt = NULL;
 611                 free_mapping_item(&sub->element.extract.item);
 612                 break;
 613         }
 614 }
 615 
 616 /*
 617  * FUNCTION:    read_line
 618  *
 619  *      Gets next line in buffer - using '\' at end of line
 620  *  to indicate continuation. Lines beginning with # are
 621  *      ignored. start_line_num and start_line_num are
 622  *      maintained to track the line number currently being
 623  *      parsed.
 624  *
 625  * RETURN VALUE:        The number of characters read. 0 for
 626  *                      eof, -1 for error
 627  *
 628  * INPUT:               file descriptor, buffer, and buffer size
 629  */
 630 
 631 int
 632 read_line(int fd, char *buffer, int buflen)
 633 {
 634         int             linelen;
 635         int             rc;
 636         char            c;
 637         bool_t          skip_line       = FALSE;
 638         bool_t          begin_line      = TRUE;
 639         static bool_t   prev_cr         = FALSE;
 640 
 641         start_line_num = cur_line_num;
 642         (void) memset(buffer, 0, buflen);
 643         for (; p_error == no_parse_error; ) {
 644                 linelen = 0;
 645                 while (linelen < buflen) {
 646                         rc = read(fd, &c, 1);
 647                         if (1 == rc) {
 648                                 if (c == '\n' || c == '\r') {
 649                                         if (c == '\n') {
 650                                                 if (prev_cr) {
 651                                                         prev_cr = FALSE;
 652                                                         continue;
 653                                                 } else {
 654                                                         if (linelen == 0)
 655                                                             start_line_num =
 656                                                                 cur_line_num;
 657                                                         else {
 658                                                                 if (
 659                                                                 is_string_ok(
 660                                                                 buffer,
 661                                                                 linelen)) {
 662                                                                 (void) memset(
 663                                                                 buffer, 0,
 664                                                                 linelen);
 665                                                                 linelen = 0;
 666                                                                 cur_line_num++;
 667                                                                 begin_line =
 668                                                                         TRUE;
 669                                                                 continue;
 670                                                                 }
 671                                                         }
 672                                                         cur_line_num++;
 673                                                 }
 674                                                 prev_cr = FALSE;
 675                                         } else {
 676                                                 prev_cr = TRUE;
 677                                                 if (linelen == 0)
 678                                                     start_line_num =
 679                                                         cur_line_num;
 680                                                 cur_line_num++;
 681                                         }
 682                                         if (skip_line) {
 683                                                 skip_line = FALSE;
 684                                                 if (linelen == 0)
 685                                                     start_line_num =
 686                                                         cur_line_num;
 687                                         } else if (linelen > 0 &&
 688                                             buffer[linelen - 1]
 689                                             == ESCAPE_CHAR) {
 690                                                 --linelen;
 691                                         } else if (linelen > 0) {
 692                                                 buffer[linelen] = '\0';
 693                                                 return (linelen);
 694                                         }
 695                                         begin_line = TRUE;
 696                                 } else {
 697                                         if (begin_line)
 698                                                 skip_line = c == POUND_SIGN;
 699                                         begin_line = FALSE;
 700                                         if (!skip_line)
 701                                                 buffer[linelen++] = c;
 702                                 }
 703                         } else {
 704                                 if (linelen > 0 &&
 705                                     buffer[linelen - 1] == ESCAPE_CHAR) {
 706                                         /* continuation on last line */
 707                                         p_error = parse_bad_continuation_error;
 708                                         return (-1);
 709                                 } else {
 710                                         buffer[linelen] = '\0';
 711                                         return (linelen);
 712                                 }
 713                         }
 714                 }
 715                 p_error = parse_line_too_long;
 716         }
 717         return (-1);
 718 }
 719 
 720 /*
 721  * FUNCTION:    finish_parse
 722  *
 723  *      Adds any elements not configured, fully qualifies
 724  *      names
 725  *
 726  * RETURN VALUE:        0 on success, -1 on failure
 727  */
 728 
 729 int
 730 finish_parse(
 731         __nis_ldap_proxy_info   *proxy_info,
 732         __nis_table_mapping_t   **table_mapping)
 733 {
 734         __nis_table_mapping_t   *t;
 735         __nis_table_mapping_t   *t1;
 736         __nis_table_mapping_t   *t2;
 737         __nis_table_mapping_t   *t_del          = NULL;
 738         int                     i;
 739         int                     j;
 740         int                     k;
 741         __nis_object_dn_t       *objectDN;
 742         __nis_mapping_rlhs_t    *lhs;
 743         __nis_mapping_element_t *e;
 744         char                    *s;
 745         int                     errnum;
 746 
 747         /* set to default those values yet set */
 748         if (proxy_info->auth_method ==
 749             (auth_method_t)NO_VALUE_SET) {
 750                 p_error = parse_no_proxy_auth_error;
 751                 report_error(NULL, NULL);
 752                 return (-1);
 753         }
 754 
 755         if (proxy_info->default_servers == NULL) {
 756                 p_error = parse_no_ldap_server_error;
 757                 report_error(NULL, NULL);
 758                 return (-1);
 759         }
 760 
 761         if (proxy_info->tls_method == (tls_method_t)NO_VALUE_SET)
 762                 proxy_info->tls_method = no_tls;
 763         else if (proxy_info->tls_method == ssl_tls &&
 764                         (proxy_info->tls_cert_db == NULL ||
 765                         *proxy_info->tls_cert_db == '\0')) {
 766                 p_error = parse_no_cert_db;
 767                 report_error(NULL, NULL);
 768                 return (-1);
 769         }
 770 
 771         if (proxy_info->default_nis_domain == NULL)
 772                 proxy_info->default_nis_domain =
 773                         s_strdup(__nis_rpc_domain());
 774         else if (*proxy_info->default_nis_domain == '\0') {
 775                 free(proxy_info->default_nis_domain);
 776                 proxy_info->default_nis_domain =
 777                         s_strdup(__nis_rpc_domain());
 778         }
 779         if (proxy_info->default_nis_domain != NULL)
 780                 append_dot(&proxy_info->default_nis_domain);
 781 
 782         if (proxy_info->tls_method == ssl_tls) {
 783                 if ((errnum = ldapssl_client_init(
 784                                 proxy_info->tls_cert_db, NULL)) < 0) {
 785                         p_error = parse_ldapssl_client_init_error;
 786                         report_error(ldapssl_err2string(errnum), NULL);
 787                         return (-1);
 788                 }
 789         }
 790 
 791         if (proxy_info->default_search_base == NULL)
 792             proxy_info->default_search_base =
 793                 get_default_ldap_base(proxy_info->default_nis_domain);
 794 
 795         /* convert a relative dn to a fullly qualified dn */
 796         (void) make_full_dn(&proxy_info->proxy_dn,
 797                 proxy_info->default_search_base);
 798 
 799         if (p_error != no_parse_error) {
 800                 report_error(NULL, NULL);
 801                 return (-1);
 802         }
 803 
 804         /*
 805          * Create a list of potential delete mappings
 806          * those have NULL objectDNs, but badly also rules
 807          * that are missing object dn's will be included.
 808          * We will use the ttl field to determine if the
 809          * delete rule is actually used
 810          */
 811         t2 = NULL;
 812         for (t = *table_mapping; t != NULL; t = t1) {
 813                 t1 = t->next;
 814                 if (t->objectDN == NULL) {
 815                         if (t2 == NULL)
 816                                 *table_mapping = t1;
 817                         else
 818                                 t2->next = t1;
 819                         t->next = t_del;
 820                         t_del = t;
 821                         t->ttl = 0;
 822                 } else
 823                         t2 = t;
 824         }
 825 
 826         for (t = *table_mapping; t != NULL; t = t->next) {
 827             objectDN = t->objectDN;
 828             while (objectDN != NULL) {
 829                 if (objectDN->dbIdName != NULL) {
 830                         s = objectDN->dbIdName;
 831                         t1 = find_table_mapping(s, strlen(s), t_del);
 832                         if (t1 == NULL) {
 833                                 p_error = parse_no_db_del_mapping_rule;
 834                                 report_error2(objectDN->dbIdName, t->dbId);
 835                                 return (-1);
 836                         } else if (t1->objName != NULL ||
 837                             t1->numRulesToLDAP == 0 ||
 838                             t1->numRulesFromLDAP != 0) {
 839                                 p_error = parse_invalid_db_del_mapping_rule;
 840                                 report_error(t1->dbId, NULL);
 841                                 return (-1);
 842                         }
 843                         objectDN->dbId =
 844                                 dup_mapping_rules(t1->ruleToLDAP,
 845                                         t1->numRulesToLDAP);
 846                         if (objectDN->dbId == NULL) {
 847                                 break;
 848                         }
 849                         objectDN->numDbIds = t1->numRulesToLDAP;
 850                         t1->ttl++;
 851                 }
 852                 objectDN = objectDN->next;
 853             }
 854         }
 855 
 856         for (t = t_del; t != NULL; t = t1) {
 857                 t1 = t->next;
 858                 if (t->ttl == 0) {
 859                         p_error = parse_no_object_dn;
 860                         report_error(t->dbId, NULL);
 861                 }
 862                 free_table_mapping(t);
 863         }
 864 
 865         if (p_error != no_parse_error)
 866                 return (-1);
 867 
 868         /* set to default those table mapping values yet set */
 869         for (t = *table_mapping; t != NULL; t = t->next) {
 870                 if (t->objName == 0) {
 871                         p_error = parse_no_object_dn;
 872                         report_error(t->dbId, NULL);
 873                         return (-1);
 874                 }
 875                 if (!yp2ldap) {
 876                         if (!add_domain(&t->objName,
 877                                         proxy_info->default_nis_domain)) {
 878                                 report_error(NULL, NULL);
 879                                 return (-1);
 880                         }
 881                 }
 882                 if (t->initTtlHi == (time_t)NO_VALUE_SET)
 883                         t->initTtlHi = DEFAULT_TTL_HIGH;
 884                 if (t->initTtlLo == (time_t)NO_VALUE_SET)
 885                         t->initTtlLo = DEFAULT_TTL_LOW;
 886                 if (t->ttl == (time_t)NO_VALUE_SET)
 887                         t->ttl = DEFAULT_TTL;
 888                 objectDN = t->objectDN;
 889 
 890                 /* fixup relative dn's */
 891                 while (objectDN != NULL) {
 892                         if (!yp2ldap) {
 893                                 if (!make_full_dn(&objectDN->read.base,
 894                                         proxy_info->default_search_base))
 895                                                 break;
 896                         }
 897                         if (objectDN->write.scope != LDAP_SCOPE_UNKNOWN) {
 898                                 if (objectDN->write.base != NULL &&
 899                                         !make_full_dn(&objectDN->write.base,
 900                                         proxy_info->default_search_base))
 901                                                 break;
 902                                 if (objectDN->write.base == NULL) {
 903                                     objectDN->write.base =
 904                                         s_strdup(objectDN->read.base);
 905                                     if (objectDN->write.base == NULL)
 906                                         break;
 907                                 }
 908                         }
 909                         objectDN = objectDN->next;
 910                 }
 911 
 912                 if (p_error != no_parse_error) {
 913                         report_error(NULL, NULL);
 914                         return (-1);
 915                 }
 916 
 917                 /* Check for ruleToLDAP with no rhs */
 918                 for (i = 0; i < t->numRulesToLDAP; i++) {
 919                     if (t->ruleToLDAP[i]->rhs.numElements == 0) {
 920                         p_error = parse_unexpected_data_end_rule;
 921                         report_error(t->dbId, NULL);
 922                         return (-1);
 923                     }
 924                 }
 925 
 926                 /* populate cols field */
 927                 if (!yp2ldap) {
 928                         for (i = 0; i < t->numRulesFromLDAP; i++) {
 929                                 lhs = &t->ruleFromLDAP[i]->lhs;
 930                                 for (j = 0; j < lhs->numElements; j++) {
 931                                         e = &lhs->element[j];
 932                                         switch (e->type) {
 933                                                 case me_item:
 934                                                 if (!add_column(t,
 935                                                 e->element.item.name)) {
 936                                                         report_error(
 937                                                         NULL, NULL);
 938                                                         return (-1);
 939                                                 }
 940                                                 break;
 941                                                 case me_match:
 942                                                 for (k = 0;
 943                                                 k < e->element.match.numItems;
 944                                                 k++)
 945                                                         if (!add_column(t,
 946                                         e->element.match.item[k].name)) {
 947                                                                 report_error(
 948                                                                 NULL, NULL);
 949                                                                 return (-1);
 950                                                         }
 951                                                 break;
 952                                         }
 953                                 }
 954                         }
 955                 }
 956         }
 957         return (0);
 958 }
 959 
 960 /*
 961  * FUNCTION:    set_default_values
 962  *
 963  *      Sets unconfigured values to their default value
 964  */
 965 
 966 void
 967 set_default_values(__nis_ldap_proxy_info *proxy_info,
 968     __nis_config_t *config_info, __nisdb_table_mapping_t *table_info)
 969 {
 970         if (proxy_info->bind_timeout.tv_sec == (time_t)NO_VALUE_SET)
 971                 proxy_info->bind_timeout.tv_sec = DEFAULT_BIND_TIMEOUT;
 972         if (proxy_info->search_timeout.tv_sec == (time_t)NO_VALUE_SET)
 973                 proxy_info->search_timeout.tv_sec =
 974                         (yp2ldap)?DEFAULT_YP_SEARCH_TIMEOUT:
 975                                 DEFAULT_SEARCH_TIMEOUT;
 976         if (proxy_info->modify_timeout.tv_sec == (time_t)NO_VALUE_SET)
 977                 proxy_info->modify_timeout.tv_sec = DEFAULT_MODIFY_TIMEOUT;
 978         if (proxy_info->add_timeout.tv_sec == (time_t)NO_VALUE_SET)
 979                 proxy_info->add_timeout.tv_sec = DEFAULT_ADD_TIMEOUT;
 980         if (proxy_info->delete_timeout.tv_sec == (time_t)NO_VALUE_SET)
 981                 proxy_info->delete_timeout.tv_sec = DEFAULT_DELETE_TIMEOUT;
 982 
 983         if (proxy_info->search_time_limit == (int)NO_VALUE_SET)
 984                 proxy_info->search_time_limit = DEFAULT_SEARCH_TIME_LIMIT;
 985         if (proxy_info->search_size_limit == (int)NO_VALUE_SET)
 986                 proxy_info->search_size_limit = DEFAULT_SEARCH_SIZE_LIMIT;
 987 
 988         if (proxy_info->follow_referral == (follow_referral_t)NO_VALUE_SET)
 989                 proxy_info->follow_referral = no_follow;
 990 
 991         switch (config_info->initialUpdate) {
 992                 case (__nis_initial_update_t)NO_VALUE_SET:
 993                 case (__nis_initial_update_t)INITIAL_UPDATE_NO_ACTION:
 994                 case (__nis_initial_update_t)NO_INITIAL_UPDATE_NO_ACTION:
 995                         config_info->initialUpdate = ini_none;
 996                         break;
 997                 case (__nis_initial_update_t)FROM_NO_INITIAL_UPDATE:
 998                         config_info->initialUpdate = from_ldap;
 999                         break;
1000                 case (__nis_initial_update_t)TO_NO_INITIAL_UPDATE:
1001                         config_info->initialUpdate = to_ldap;
1002                         break;
1003         }
1004         if (config_info->threadCreationError ==
1005             (__nis_thread_creation_error_t)NO_VALUE_SET)
1006                 config_info->threadCreationError = pass_error;
1007         if (config_info->threadCreationErrorTimeout.attempts == NO_VALUE_SET)
1008                 config_info->threadCreationErrorTimeout.attempts =
1009                         DEFAULT_THREAD_ERROR_ATTEMPTS;
1010         if (config_info->threadCreationErrorTimeout.timeout ==
1011                         (time_t)NO_VALUE_SET)
1012                 config_info->threadCreationErrorTimeout.timeout =
1013                         DEFAULT_THREAD_ERROR_TIME_OUT;
1014         if (config_info->dumpError ==
1015             (__nis_dump_error_t)NO_VALUE_SET)
1016                 config_info->dumpError = de_retry;
1017         if (config_info->dumpErrorTimeout.attempts == NO_VALUE_SET)
1018                 config_info->dumpErrorTimeout.attempts =
1019                         DEFAULT_DUMP_ERROR_ATTEMPTS;
1020         if (config_info->dumpErrorTimeout.timeout == (time_t)NO_VALUE_SET)
1021                 config_info->dumpErrorTimeout.timeout =
1022                         DEFAULT_DUMP_ERROR_TIME_OUT;
1023         if (config_info->resyncService ==
1024             (__nis_resync_service_t)NO_VALUE_SET)
1025                 config_info->resyncService = from_copy;
1026         if (config_info->updateBatching ==
1027             (__nis_update_batching_t)NO_VALUE_SET)
1028                 config_info->updateBatching = accumulate;
1029         if (config_info->updateBatchingTimeout.timeout == (time_t)NO_VALUE_SET)
1030                 config_info->updateBatchingTimeout.timeout =
1031                         DEFAULT_BATCHING_TIME_OUT;
1032         if (config_info->numberOfServiceThreads == (int)NO_VALUE_SET)
1033                 config_info->numberOfServiceThreads =
1034                         DEFAULT_NUMBER_OF_THREADS;
1035         if (config_info->emulate_yp == (int)NO_VALUE_SET)
1036                 config_info->emulate_yp =
1037                         DEFAULT_YP_EMULATION;
1038         if (config_info->maxRPCRecordSize == (int)NO_VALUE_SET)
1039                 config_info->maxRPCRecordSize = RPC_MAXDATASIZE;
1040 
1041         if (table_info->retrieveError ==
1042             (__nis_retrieve_error_t)NO_VALUE_SET)
1043                 table_info->retrieveError = use_cached;
1044         if (table_info->retrieveErrorRetry.attempts == NO_VALUE_SET)
1045                 table_info->retrieveErrorRetry.attempts =
1046                         DEFAULT_RETRIEVE_ERROR_ATTEMPTS;
1047         if (table_info->retrieveErrorRetry.timeout == (time_t)NO_VALUE_SET)
1048                 table_info->retrieveErrorRetry.timeout =
1049                         DEFAULT_RETRIEVE_ERROR_TIME_OUT;
1050         if (table_info->storeError ==
1051             (__nis_store_error_t)NO_VALUE_SET)
1052                 table_info->storeError = sto_retry;
1053         if (table_info->storeErrorRetry.attempts == NO_VALUE_SET)
1054                 table_info->storeErrorRetry.attempts =
1055                         DEFAULT_STORE_ERROR_ATTEMPTS;
1056         if (table_info->storeErrorRetry.timeout == (time_t)NO_VALUE_SET)
1057                 table_info->storeErrorRetry.timeout =
1058                         DEFAULT_STORE_ERROR_TIME_OUT;
1059         if (table_info->refreshError ==
1060             (__nis_refresh_error_t)NO_VALUE_SET)
1061                 table_info->refreshError = continue_using;
1062         if (table_info->refreshErrorRetry.attempts == NO_VALUE_SET)
1063                 table_info->refreshErrorRetry.attempts =
1064                         DEFAULT_REFRESH_ERROR_ATTEMPTS;
1065         if (table_info->refreshErrorRetry.timeout == (time_t)NO_VALUE_SET)
1066                 table_info->refreshErrorRetry.timeout =
1067                         DEFAULT_REFRESH_ERROR_TIME_OUT;
1068         if (table_info->matchFetch ==
1069             (__nis_match_fetch_t)NO_VALUE_SET)
1070                 table_info->matchFetch = no_match_only;
1071 }
1072 
1073 __nis_table_mapping_t *
1074 find_table_mapping(const char *s, int len, __nis_table_mapping_t *table_mapping)
1075 {
1076         __nis_table_mapping_t *t;
1077 
1078         for (t = table_mapping; t != NULL; t = t->next)
1079                 if (strlen(t->dbId) == len &&
1080                     strncasecmp(t->dbId, s, len) == 0)
1081                         break;
1082         return (t);
1083 }
1084 
1085 void
1086 append_dot(char **str)
1087 {
1088         char    *s      = *str;
1089         int     len     = strlen(s);
1090 
1091         if (len == 0 || s[len - 1] != PERIOD_CHAR) {
1092                 s = s_realloc(s, len + 2);
1093                 if (s != NULL) {
1094                         s[len] = PERIOD_CHAR;
1095                         s[len+1] = '\0';
1096                         *str = s;
1097                 }
1098         }
1099 }
1100 
1101 void
1102 append_comma(char **str)
1103 {
1104 
1105         char    *s  = *str;
1106         int len = strlen(s);
1107 
1108         if (len == 0 || s[len - 1] != COMMA_CHAR) {
1109                 s = s_realloc(s, len + 2);
1110                 if (s != NULL) {
1111                         s[len] = COMMA_CHAR;
1112                         s[len+1] = '\0';
1113                         *str = s;
1114                 }
1115         }
1116 }
1117 
1118 /*
1119  * FUNCTION:    make_full_dn
1120  *
1121  *      Appends the base dn if a relative ldap dn
1122  *      (invoked only for LDAP write cycle)
1123  *
1124  * RETURN VALUE:        FALSE if error
1125  *                      TRUE if __nis_index_t returned
1126  *
1127  * INPUT:               the relative dn and ldap base
1128  */
1129 
1130 bool_t
1131 make_full_dn(char **dn, const char *base)
1132 {
1133         int len;
1134         int len1;
1135 
1136         if (*dn == NULL) {
1137                 *dn = s_strdup(base);
1138         } else {
1139                 len = strlen(*dn);
1140                 if (len > 0 && (*dn)[len-1] == COMMA_CHAR) {
1141                         len1 = strlen(base) + 1;
1142                         *dn = s_realloc(*dn, len + len1);
1143                         if (*dn != NULL)
1144                                 (void) strcpy(*dn + len, base);
1145                 }
1146         }
1147         return (*dn != NULL);
1148 }
1149 
1150 /*
1151  * FUNCTION:    make_fqdn
1152  *
1153  *      Appends the base dn if a relative ldap dn
1154  *      (invoked only for LDAP read cycle)
1155  *
1156  * RETURN VALUE:        FALSE if error
1157  *                      TRUE if success
1158  *
1159  * INPUT:               the relative dn and ldap base
1160  */
1161 bool_t
1162 make_fqdn(__nis_object_dn_t *dn, const char *base)
1163 {
1164         int len;
1165         int len1;
1166 
1167         if (dn == NULL) {
1168                 return (FALSE);
1169         } else {
1170                 while (dn != NULL && dn->read.base != NULL) {
1171                         len = strlen(dn->read.base);
1172                         if (len > 0 && (dn->read.base)[len-1] == COMMA_CHAR) {
1173                                 len1 = strlen(base) + 1;
1174                                 dn->read.base =
1175                                         s_realloc(dn->read.base, len + len1);
1176                                 if (dn->read.base != NULL)
1177                                         (void) strlcpy(dn->read.base + len,
1178                                                         base, len1);
1179                                 else
1180                                         return (FALSE);
1181                         }
1182                         dn = dn->next;
1183                 }
1184         }
1185         return (TRUE);
1186 }
1187 
1188 /*
1189  * FUNCTION:    get_default_ldap_base
1190  *
1191  *      Gets the default LDAP search base from the
1192  *      nis+ default domain
1193  *
1194  * RETURN VALUE:        NULL if error
1195  *                      the default base
1196  *
1197  * INPUT:               the nis domain
1198  */
1199 
1200 char *
1201 get_default_ldap_base(const char *domain)
1202 {
1203 
1204         int             len     = strlen(domain);
1205         int             i;
1206         int             count   = len + 4;
1207         char            *base;
1208 
1209         for (i = 0; i < len - 1; i++)
1210                 if (domain[i] == PERIOD_CHAR)
1211                         count += 4;
1212         if ((base = malloc(count)) == NULL) {
1213                 p_error = parse_no_mem_error;
1214         } else {
1215                 (void) strcpy(base, "dc=");
1216                 count = 3;
1217                 for (i = 0; i < len - 1; i++) {
1218                         if (domain[i] == PERIOD_CHAR) {
1219                                 (void) strcpy(base + count, ",dc=");
1220                                 count += 4;
1221                         } else {
1222                                 base[count++] = domain[i];
1223                         }
1224                 }
1225                 base[count] = '\0';
1226         }
1227         return (base);
1228 }
1229 
1230 /*
1231  * FUNCTION:    add_domain
1232  *
1233  *      Appends the base domain if a relative object name
1234  *
1235  * RETURN VALUE:        FALSE if error
1236  *                      TRUE if OK
1237  *
1238  * INPUT:               the relative object name and base domain
1239  *                      name
1240  */
1241 
1242 bool_t
1243 add_domain(char **objName, const char *domain)
1244 {
1245         int     len;
1246         int     len1;
1247         bool_t  trailing_dot;
1248         char    *obj_name;
1249 
1250         if (domain == NULL || *objName == NULL) {
1251                 p_error = parse_internal_error;
1252                 return (FALSE);
1253         }
1254         len1 = strlen(domain);
1255         trailing_dot = (len1 > 0 && domain[len1 - 1] == PERIOD_CHAR) ?
1256                 0 : 1;
1257         len = strlen(*objName);
1258         if (len == 0 || (*objName)[len - 1] != PERIOD_CHAR) {
1259                 obj_name = s_realloc(*objName,
1260                         len + len1 + 2 + trailing_dot);
1261                 if (obj_name != NULL) {
1262                         obj_name[len++] = PERIOD_CHAR;
1263                         (void) strcpy(obj_name + len, domain);
1264                         if (trailing_dot != 0) {
1265                                 obj_name[len + len1] = PERIOD_CHAR;
1266                                 obj_name[len + len1 + 1] = '\0';
1267                         }
1268                         *objName = obj_name;
1269                 }
1270         }
1271 
1272         return (*objName != NULL);
1273 }
1274 
1275 bool_t
1276 dup_index(__nis_index_t *in, __nis_index_t *out)
1277 {
1278         int i;
1279         int j;
1280 
1281         out->name = (char **)s_calloc(in->numIndexes, sizeof (char *));
1282         if (out->name == NULL)
1283                 return (FALSE);
1284         out->value = (__nis_mapping_format_t **)
1285                 s_calloc(in->numIndexes, sizeof (__nis_mapping_format_t *));
1286         if (out->value == NULL) {
1287                 free(out->name);
1288                 out->name = NULL;
1289                 return (FALSE);
1290         }
1291 
1292         for (i = 0; i < in->numIndexes; i++) {
1293                 out->name[i] = s_strdup(in->name[i]);
1294                 if (out->name[i] == NULL)
1295                         break;
1296                 out->value[i] = dup_format_mapping(in->value[i]);
1297                 if (out->value[i] == NULL)
1298                         break;
1299         }
1300         if (i < in->numIndexes) {
1301                 for (j = 0; j <= i; j++) {
1302                         if (out->name[j] != NULL)
1303                                 free(out->name[j]);
1304                         if (out->value[j] != NULL)
1305                                 free_mapping_format(out->value[j]);
1306                 }
1307                 free(out->name);
1308                 out->name = NULL;
1309                 free(out->value);
1310                 out->value = NULL;
1311         } else {
1312                 out->numIndexes = in->numIndexes;
1313         }
1314         return (i == in->numIndexes);
1315 }
1316 
1317 bool_t
1318 dup_mapping_item(__nis_mapping_item_t *in, __nis_mapping_item_t *out)
1319 {
1320         bool_t  ret;
1321 
1322         if (in->type == mit_nisplus) {
1323                 ret = dup_index(&in->searchSpec.obj.index,
1324                         &out->searchSpec.obj.index);
1325                 if (!ret)
1326                         return (ret);
1327                 if (in->searchSpec.obj.name != NULL) {
1328                     out->searchSpec.obj.name =
1329                         s_strdup(in->searchSpec.obj.name);
1330                         if (out->searchSpec.obj.name == NULL)
1331                                 return (FALSE);
1332                 } else
1333                         out->searchSpec.obj.name = NULL;
1334         } else if (in->type == mit_ldap) {
1335                 if (in->searchSpec.triple.base != NULL) {
1336                     out->searchSpec.triple.base =
1337                         s_strdup(in->searchSpec.triple.base);
1338                         if (out->searchSpec.triple.base == NULL)
1339                                 return (FALSE);
1340                 } else
1341                         out->searchSpec.triple.base = NULL;
1342                 out->searchSpec.triple.scope =
1343                         in->searchSpec.triple.scope;
1344                 if (in->searchSpec.triple.attrs != NULL) {
1345                     out->searchSpec.triple.attrs =
1346                         s_strdup(in->searchSpec.triple.attrs);
1347                         if (out->searchSpec.triple.attrs == NULL)
1348                                 return (FALSE);
1349                 } else
1350                         out->searchSpec.triple.attrs = NULL;
1351                 if (in->searchSpec.triple.element != NULL) {
1352                         out->searchSpec.triple.element =
1353                                 (__nis_mapping_element_t *)
1354                                 s_calloc(1, sizeof (__nis_mapping_element_t));
1355                         if (out->searchSpec.triple.element != NULL)
1356                                 dup_mapping_element(
1357                                         in->searchSpec.triple.element,
1358                                         out->searchSpec.triple.element);
1359                         if (out->searchSpec.triple.element == NULL)
1360                                 return (FALSE);
1361                 } else
1362                         out->searchSpec.triple.element = NULL;
1363         }
1364 
1365         if (in->name != NULL) {
1366                 out->name = s_strdup(in->name);
1367                 if (out->name == NULL)
1368                         return (FALSE);
1369         } else
1370                 out->name = NULL;
1371         out->type = in->type;
1372         out->repeat = in->repeat;
1373         if (in->exItem) {
1374                 out->exItem = (__nis_mapping_item_t *)s_malloc
1375                         (sizeof (__nis_mapping_item_t));
1376                 if (out->exItem == NULL)
1377                         return (FALSE);
1378                 else {
1379                         (void) memset
1380                                 (out->exItem, 0, sizeof (out->exItem[0]));
1381                         if (!dup_mapping_item
1382                                 (in->exItem, out->exItem))
1383                                 p_error = parse_internal_error;
1384                 }
1385         } else
1386                 out->exItem = NULL;
1387 
1388         return (p_error == no_parse_error);
1389 }
1390 
1391 __nis_mapping_format_t *
1392 dup_format_mapping(__nis_mapping_format_t *in)
1393 {
1394         int                     i;
1395         __nis_mapping_format_t  *out;
1396         bool_t                  got_end;
1397 
1398         i = 0;
1399         while (in[i].type != mmt_end)
1400                 i++;
1401         out = (__nis_mapping_format_t *)s_calloc(
1402                 i + 1, sizeof (__nis_mapping_format_t));
1403         if (out != NULL) {
1404                 got_end = FALSE;
1405                 for (i = 0; !got_end; i++) {
1406                     switch (in[i].type) {
1407                         case mmt_item:
1408                                 break;
1409                         case mmt_string:
1410                                 out[i].match.string =
1411                                         s_strdup(in[i].match.string);
1412                                 break;
1413                         case mmt_single:
1414                                 out[i].match.single.numRange =
1415                                         in[i].match.single.numRange;
1416                                 out[i].match.single.lo =
1417                                         s_malloc(in[i].match.single.numRange);
1418                                 if (out[i].match.single.lo == NULL)
1419                                         break;
1420                                 out[i].match.single.hi =
1421                                         s_malloc(in[i].match.single.numRange);
1422                                 if (out[i].match.single.hi == NULL)
1423                                         break;
1424                                 memcpy(out[i].match.single.lo,
1425                                         in[i].match.single.lo,
1426                                         in[i].match.single.numRange);
1427                                 memcpy(out[i].match.single.hi,
1428                                         in[i].match.single.hi,
1429                                         in[i].match.single.numRange);
1430                                 break;
1431                         case mmt_limit:
1432                                 out[i].match.limit = in[i].match.limit;
1433                                 break;
1434                         case mmt_any:
1435                                 break;
1436                         case mmt_berstring:
1437                                 out[i].match.berString =
1438                                         s_strdup(in[i].match.berString);
1439                                 break;
1440                         case mmt_begin:
1441                                 break;
1442                         case mmt_end:
1443                                 got_end = TRUE;
1444                                 break;
1445                         default:
1446                                 p_error = parse_internal_error;
1447                     }
1448                     if (p_error != no_parse_error)
1449                         break;
1450                     out[i].type = in[i].type;
1451                 }
1452                 if (p_error != no_parse_error) {
1453                         free_mapping_format(out);
1454                         out = NULL;
1455                 }
1456         }
1457 
1458         return (out);
1459 }
1460 
1461 bool_t
1462 dup_mapping_sub_element(
1463         __nis_mapping_sub_element_t     *in,
1464         __nis_mapping_sub_element_t     *out)
1465 {
1466         bool_t  ret = FALSE;
1467         int     i;
1468 
1469         switch (in->type) {
1470                 case me_item:
1471                         ret = dup_mapping_item(&in->element.item,
1472                                 &out->element.item);
1473                         break;
1474                 case me_print:
1475                         out->element.print.fmt =
1476                                 dup_format_mapping(in->element.print.fmt);
1477                         if (out->element.print.fmt == NULL)
1478                                 break;
1479                         out->element.print.numItems =
1480                                 in->element.print.numItems;
1481                         out->element.print.item = (__nis_mapping_item_t *)
1482                                 s_calloc(in->element.print.numItems,
1483                                         sizeof (__nis_mapping_item_t));
1484                         if (out->element.print.item == NULL)
1485                                 break;
1486                         for (i = 0; i < in->element.print.numItems; i++)
1487                                 if (!dup_mapping_item(
1488                                         &in->element.print.item[i],
1489                                         &out->element.print.item[i]))
1490                                                 break;
1491                         if (i < in->element.print.numItems)
1492                                 break;
1493                         ret = TRUE;
1494                         out->element.print.doElide = in->element.print.doElide;
1495                         out->element.print.elide = in->element.print.elide;
1496                         break;
1497                 case me_split:
1498                         ret = dup_mapping_item(&in->element.split.item,
1499                                 &out->element.split.item);
1500                         out->element.split.delim = in->element.split.delim;
1501                         break;
1502                 case me_extract:
1503                         out->element.extract.fmt =
1504                                 dup_format_mapping(in->element.extract.fmt);
1505                         if (out->element.extract.fmt == NULL)
1506                                 break;
1507                         ret = dup_mapping_item(&in->element.extract.item,
1508                                 &out->element.extract.item);
1509                         break;
1510                 default:
1511                         p_error = parse_internal_error;
1512         }
1513         out->type = in->type;
1514 
1515         return (ret);
1516 }
1517 
1518 bool_t
1519 dup_mapping_element(
1520         __nis_mapping_element_t *in,
1521         __nis_mapping_element_t *out)
1522 {
1523         bool_t  ret = FALSE;
1524         int     i;
1525 
1526         if (in == NULL)
1527                 return (ret);
1528 
1529         switch (in->type) {
1530                 case me_item:
1531                         ret = dup_mapping_item(&in->element.item,
1532                                 &out->element.item);
1533                         break;
1534                 case me_print:
1535                         out->element.print.fmt =
1536                                 dup_format_mapping(in->element.print.fmt);
1537                         if (out->element.print.fmt == NULL)
1538                                 break;
1539                         out->element.print.numSubElements =
1540                                 in->element.print.numSubElements;
1541                         out->element.print.subElement =
1542                                 (__nis_mapping_sub_element_t *)
1543                                 s_calloc(in->element.print.numSubElements,
1544                                         sizeof (__nis_mapping_sub_element_t));
1545                         if (out->element.print.subElement == NULL)
1546                                 break;
1547                         for (i = 0; i < in->element.print.numSubElements; i++)
1548                                 if (!dup_mapping_sub_element(
1549                                         &in->element.print.subElement[i],
1550                                         &out->element.print.subElement[i]))
1551                                                 break;
1552                         if (i < in->element.print.numSubElements)
1553                                 break;
1554                         ret = TRUE;
1555                         out->element.print.doElide = in->element.print.doElide;
1556                         out->element.print.elide = in->element.print.elide;
1557                         break;
1558                 case me_split:
1559                         ret = dup_mapping_item(&in->element.split.item,
1560                                 &out->element.split.item);
1561                         out->element.split.delim = in->element.split.delim;
1562                         break;
1563                 case me_match:
1564                         out->element.match.fmt =
1565                                 dup_format_mapping(in->element.match.fmt);
1566                         if (out->element.match.fmt == NULL)
1567                                 break;
1568                         out->element.match.numItems =
1569                                 in->element.match.numItems;
1570                         out->element.match.item = (__nis_mapping_item_t *)
1571                                 s_calloc(in->element.match.numItems,
1572                                         sizeof (__nis_mapping_item_t));
1573                         if (out->element.match.item == NULL)
1574                                 break;
1575                         for (i = 0; i < in->element.match.numItems; i++)
1576                                 if (!dup_mapping_item(
1577                                         &in->element.match.item[i],
1578                                         &out->element.match.item[i]))
1579                                                 break;
1580                         if (i < in->element.match.numItems)
1581                                 break;
1582                         ret = TRUE;
1583                         break;
1584                 case me_extract:
1585                         out->element.extract.fmt =
1586                                 dup_format_mapping(in->element.extract.fmt);
1587                         if (out->element.extract.fmt == NULL)
1588                                 break;
1589                         ret = dup_mapping_item(&in->element.extract.item,
1590                                 &out->element.extract.item);
1591                         break;
1592                 default:
1593                         p_error = parse_internal_error;
1594         }
1595         out->type = in->type;
1596 
1597         return (ret);
1598 }
1599 
1600 __nis_mapping_rule_t *
1601 dup_mapping_rule(__nis_mapping_rule_t *in)
1602 {
1603         int                     i;
1604         __nis_mapping_rlhs_t    *r_in;
1605         __nis_mapping_rlhs_t    *r_out;
1606         __nis_mapping_rule_t    *out;
1607 
1608         out = (__nis_mapping_rule_t *)
1609                 s_calloc(1, sizeof (__nis_mapping_rule_t));
1610         if (out != NULL) {
1611                 r_in = &in->lhs;
1612                 r_out = &out->lhs;
1613                 r_out->numElements = r_in->numElements;
1614                 r_out->element = (__nis_mapping_element_t *)s_calloc
1615                         (r_in->numElements, sizeof (__nis_mapping_element_t));
1616                 if (r_out->element == NULL) {
1617                         free_mapping_rule(out);
1618                         return (NULL);
1619                 }
1620                 for (i = 0; i < r_in->numElements; i++) {
1621                     if (!dup_mapping_element(&r_in->element[i],
1622                         &r_out->element[i]))
1623                                 break;
1624                 }
1625                 if (i < r_in->numElements) {
1626                         free_mapping_rule(out);
1627                         return (NULL);
1628                 }
1629 
1630                 r_in = &in->rhs;
1631                 r_out = &out->rhs;
1632                 r_out->numElements = r_in->numElements;
1633                 r_out->element = (__nis_mapping_element_t *)s_calloc
1634                         (r_in->numElements, sizeof (__nis_mapping_element_t));
1635                 if (r_out->element == NULL) {
1636                         free_mapping_rule(out);
1637                         return (NULL);
1638                 }
1639                 for (i = 0; i < r_in->numElements; i++) {
1640                     if (!dup_mapping_element(&r_in->element[i],
1641                         &r_out->element[i]))
1642                                 break;
1643                 }
1644                 if (i < r_in->numElements) {
1645                         free_mapping_rule(out);
1646                         return (NULL);
1647                 }
1648         }
1649         return (out);
1650 }
1651 
1652 __nis_mapping_rule_t **
1653 dup_mapping_rules(__nis_mapping_rule_t **rules, int n_rules)
1654 {
1655         int                     i, j;
1656         __nis_mapping_rule_t    **r;
1657 
1658         r = (__nis_mapping_rule_t **)s_calloc(n_rules,
1659                 sizeof (__nis_mapping_rule_t *));
1660         if (r != NULL) {
1661                 for (i = 0; i < n_rules; i++) {
1662                         r[i] = dup_mapping_rule(rules[i]);
1663                         if (r[i] == NULL) {
1664                                 for (j = 0; j < i; j++)
1665                                         free_mapping_rule(r[j]);
1666                                 free(r);
1667                                 r = NULL;
1668                                 break;
1669                         }
1670                 }
1671         }
1672         return (r);
1673 }
1674 
1675 /*
1676  * FUNCTION:    add_column
1677  *
1678  *      Adds a column name to the column list in __nis_table_mapping_t
1679  *
1680  * RETURN VALUE:        FALSE if error
1681  *                      TRUE if __nis_index_t returned
1682  *
1683  * INPUT:               the __nis_table_mapping_t and column name
1684  */
1685 
1686 bool_t
1687 add_column(__nis_table_mapping_t *t, const char *col_name)
1688 {
1689         int i;
1690         char **cols = NULL;
1691 
1692         if (!yp2ldap) {
1693                 for (i = 0; i < t->numColumns; i++) {
1694                         if (strcasecmp(col_name, t->column[i]) == 0)
1695                                 return (TRUE);
1696                 }
1697         }
1698         cols = (char **)s_realloc(t->column, (t->numColumns + 1) *
1699                 sizeof (char *));
1700         if (cols == NULL)
1701                 return (FALSE);
1702         t->column = cols;
1703         cols[t->numColumns] = s_strdup(col_name);
1704         if (cols[t->numColumns] == NULL)
1705                 return (FALSE);
1706         t->numColumns++;
1707         return (TRUE);
1708 }
1709 
1710 /*
1711  * FUNCTION:    add_element
1712  *
1713  *      Adds a __nis_mapping_element_t to __nis_mapping_rlhs_t
1714  *
1715  * RETURN VALUE:        FALSE if error
1716  *                      TRUE if __nis_index_t returned
1717  *
1718  * INPUT:               the __nis_mapping_element_t and
1719  *                      __nis_mapping_rlhs_t
1720  */
1721 
1722 bool_t
1723 add_element(
1724         __nis_mapping_element_t *e,
1725         __nis_mapping_rlhs_t    *m)
1726 {
1727         __nis_mapping_element_t *e1;
1728         int                     i;
1729         int                     n       = m->numElements;
1730 
1731         e1 = (__nis_mapping_element_t *)s_realloc(m->element,
1732                 (n + 1) * sizeof (__nis_mapping_element_t));
1733         if (e1 == NULL) {
1734                 e1 = m->element;
1735                 for (i = 0; i < n; i++)
1736                         free_mapping_element(e1++);
1737                 if (m->element != NULL)
1738                         free(m->element);
1739                 m->element = NULL;
1740                 m->numElements = 0;
1741         } else {
1742                 e1[m->numElements++] = *e;
1743                 free(e);
1744                 m->element = (__nis_mapping_element_t *)e1;
1745         }
1746         return (e1 != NULL);
1747 }
1748 
1749 /*
1750  * FUNCTION:    get_next_object_dn_token
1751  *
1752  *      Get the next token in parsing object_dn
1753  *
1754  * RETURN VALUE:        NULL if error
1755  *                      position of beginning next token after
1756  *                      token
1757  *
1758  * INPUT:               the attribute value
1759  */
1760 
1761 const char *
1762 get_next_object_dn_token(
1763         const char      **begin_ret,
1764         const char      **end_ret,
1765         object_dn_token *token)
1766 {
1767         object_dn_token t               = dn_no_token;
1768         const char      *s              = *begin_ret;
1769         const char      *begin;
1770         const char      *end            = *end_ret;
1771         const char      *s1;
1772         bool_t          in_quotes;
1773 
1774         while (s < end && is_whitespace(*s))
1775                 s++;
1776         if (s >= end) {
1777                 /* EMPTY */
1778         } else if (*s == SEMI_COLON_CHAR) {
1779                 t = dn_semi_token;
1780                 s++;
1781         } else if (*s == QUESTION_MARK) {
1782                 t = dn_ques_token;
1783                 s++;
1784         } else if (*s == COLON_CHAR) {
1785                 t = dn_colon_token;
1786                 s++;
1787         } else if (*s == OPEN_PAREN_CHAR) {
1788                 begin = s;
1789                 s = get_ldap_filter(&begin, &end);
1790                 if (s != NULL) {
1791                         t = dn_text_token;
1792                         *begin_ret = begin;
1793                         *end_ret = end;
1794                 }
1795         } else {
1796                 begin = s;
1797                 in_quotes = FALSE;
1798                 while (s < end) {
1799                         if (*s == ESCAPE_CHAR) {
1800                             if (s + 2 > end) {
1801                                 p_error = parse_unmatched_escape;
1802                                 s = NULL;
1803                                 break;
1804                             }
1805                             s++;
1806                         } else if (*s == DOUBLE_QUOTE_CHAR) {
1807                                 in_quotes = ! in_quotes;
1808                         } else if (in_quotes)
1809                                 ;
1810                         else if (*s == SEMI_COLON_CHAR ||
1811                                 *s == QUESTION_MARK ||
1812                                 *s == COLON_CHAR)
1813                                         break;
1814                         s++;
1815                 }
1816                 if (s != NULL) {
1817                         s1 = s - 1;
1818                         while (is_whitespace(*s1))
1819                                 s1--;
1820                         s1++;
1821                         if (same_string("base", begin, s1 - begin))
1822                                 t = dn_base_token;
1823                         else if (same_string("one", begin, s1 - begin))
1824                                 t = dn_one_token;
1825                         else if (same_string("sub", begin, s1 - begin))
1826                                 t = dn_sub_token;
1827                         else
1828                                 t = dn_text_token;
1829                         *begin_ret = begin;
1830                         *end_ret = s1;
1831                 }
1832         }
1833         *token = t;
1834         return (s);
1835 }
1836 
1837 /*
1838  * FUNCTION:    get_next_token
1839  *
1840  *      Get the next token in parsing mapping attribute
1841  *
1842  * RETURN VALUE:        NULL if error
1843  *                      position of beginning next token after
1844  *                      token
1845  *
1846  * INPUT:               the attribute value
1847  */
1848 
1849 const char *
1850 get_next_token(const char **begin_token, const char **end_token, token_type *t)
1851 {
1852         const char      *s              = *begin_token;
1853         const char      *end_s          = *end_token;
1854         const char      *s_begin;
1855 
1856         while (s < end_s && is_whitespace(*s))
1857                 s++;
1858         if (s == end_s) {
1859                 *t = no_token;
1860                 return (s);
1861         }
1862 
1863         s_begin = s;
1864 
1865         if (*s == OPEN_PAREN_CHAR) {
1866                 *begin_token = s;
1867                 s++;
1868                 *end_token = s;
1869                 while (s < end_s && is_whitespace(*s))
1870                         s++;
1871                 *t = open_paren_token;
1872         } else if (*s == DOUBLE_QUOTE_CHAR) {
1873                 s++;
1874                 while (s < end_s) {
1875                         if (*s == ESCAPE_CHAR)
1876                                 s += 2;
1877                         else if (*s == DOUBLE_QUOTE_CHAR)
1878                                 break;
1879                         else
1880                                 s++;
1881                 }
1882                 if (s >= end_s) {
1883                         p_error = parse_unmatched_escape;
1884                         return (NULL);
1885                 }
1886 
1887                 *t = quoted_string_token;
1888                 *begin_token = s_begin + 1;
1889                 *end_token = s++;
1890         } else if (*s == EQUAL_CHAR || *s == COMMA_CHAR ||
1891             *s == CLOSE_PAREN_CHAR || *s == COLON_CHAR) {
1892                 if (*s == EQUAL_CHAR)
1893                         *t = equal_token;
1894                 else if (*s == COMMA_CHAR)
1895                         *t = comma_token;
1896                 else if (*s == CLOSE_PAREN_CHAR)
1897                         *t = close_paren_token;
1898                 else
1899                         *t = colon_token;
1900                 *begin_token = s;
1901                 *end_token = ++s;
1902         } else {
1903                 s_begin = s;
1904                 while (s < end_s && !is_whitespace(*s)) {
1905                         if (*s == ESCAPE_CHAR)
1906                                 s += 2;
1907                         else if (*s == EQUAL_CHAR || *s == CLOSE_PAREN_CHAR ||
1908                             *s == OPEN_PAREN_CHAR || *s == COMMA_CHAR ||
1909                             *s == COLON_CHAR || *s == OPEN_BRACKET ||
1910                             *s == CLOSE_BRACKET)
1911                                 break;
1912                         else
1913                                 s++;
1914                 }
1915                 if (s > end_s) {
1916                         p_error = parse_unmatched_escape;
1917                         return (NULL);
1918                 }
1919                 *t = string_token;
1920                 *end_token = s;
1921                 *begin_token = s_begin;
1922         }
1923         if (s) {
1924                 while (s < end_s && is_whitespace(*s))
1925                         s++;
1926         }
1927         return (s);
1928 }
1929 
1930 /*
1931  * FUNCTION:    skip_token
1932  *
1933  *      Skip over the specified token - An error is set if
1934  *      next token does not match expected token
1935  *
1936  * RETURN VALUE:        NULL if error
1937  *                      position of beginning next token after
1938  *                      token
1939  *
1940  * INPUT:               the attribute value
1941  */
1942 
1943 const char *
1944 skip_token(const char *s, const char *end_s, token_type t)
1945 {
1946         bool_t  match;
1947         char    c       = 0;
1948 
1949         if (s == NULL)
1950                 return (s);
1951         while (s < end_s && is_whitespace(*s))
1952                 s++;
1953         c = (s == end_s) ? 0 : *s;
1954         switch (t) {
1955                 case equal_token:
1956                         match = c == EQUAL_CHAR;
1957                         if (!match)
1958                                 p_error = parse_equal_expected_error;
1959                         break;
1960                 case comma_token:
1961                         match = c == COMMA_CHAR;
1962                         if (!match)
1963                                 p_error = parse_comma_expected_error;
1964                         break;
1965                 case close_paren_token:
1966                         match = c == CLOSE_PAREN_CHAR;
1967                         if (!match)
1968                                 p_error = parse_close_paren_expected_error;
1969                         break;
1970                 default:
1971                         match = FALSE;
1972                         break;
1973         }
1974         if (match) {
1975                 s++;
1976                 while (s < end_s && is_whitespace(*s))
1977                         s++;
1978         } else {
1979                 s = NULL;
1980         }
1981         return (s);
1982 }
1983 
1984 /*
1985  * FUNCTION:    get_next_extract_format_item
1986  *
1987  *      Get the next format token from the string. Note that
1988  *      get_next_extract_format_item may change the input string.
1989  *
1990  * RETURN VALUE:        NULL if error
1991  *                      position of beginning next token after
1992  *                      token
1993  *
1994  * INPUT:               the format string
1995  */
1996 
1997 const char *
1998 get_next_extract_format_item(
1999         const char              *begin_fmt,
2000         const char              *end_fmt,
2001         __nis_mapping_format_t  *fmt)
2002 {
2003         const char      *s              = begin_fmt;
2004         const char      *s_end          = end_fmt;
2005         bool_t          escape;
2006         bool_t          in_range;
2007         bool_t          got_char;
2008         bool_t          done;
2009         int             numRange;
2010         char            *lo             = NULL;
2011         char            *hi             = NULL;
2012         bool_t          skip_ber;
2013 
2014         for (; p_error == no_parse_error; ) {
2015                 if (s >= s_end)
2016                         break;
2017 
2018                 if (*s == PERCENT_SIGN) {
2019                         s++;
2020                         /*
2021                          * If the format is %s, it is interpreted
2022                          * as a string.
2023                          */
2024                         if (s >= s_end) {
2025                                 p_error = parse_unsupported_format;
2026                                 break;
2027                         }
2028                         skip_ber = FALSE;
2029                         switch (*s) {
2030                                 case 's':
2031                                         fmt->type = mmt_item;
2032                                         break;
2033                                 case 'n':       /* null */
2034                                 case 'x':       /* skip the next element */
2035                                         skip_ber = TRUE;
2036                                         /* FALLTHRU */
2037                                 case 'b':       /* boolean */
2038                                 case 'e':       /* enumerated */
2039                                 case 'i':       /* int */
2040                                 case 'o':       /* octet string */
2041                                 case 'B':       /* bit string */
2042                                         fmt->match.berString = s_strndup(s, 1);
2043                                         fmt->type = skip_ber ?
2044                                                 mmt_berstring_null :
2045                                                 mmt_berstring;
2046                                         break;
2047                                 case 'a':       /* octet string */
2048                                         if (yp2ldap) {
2049                                                 fmt->match.berString =
2050                                                         s_strndup(s, 1);
2051                                                 fmt->type = skip_ber ?
2052                                                         mmt_berstring_null :
2053                                                         mmt_berstring;
2054                                                 break;
2055                                         } /* else FALLTHRU */
2056                                 case '{':       /* begin sequence */
2057                                 case '[':       /* begin set */
2058                                 case '}':       /* end sequence */
2059                                 case ']':       /* end set */
2060                                 case 'l':       /* length of next item */
2061                                 case 'O':       /* octet string */
2062                                 case 't':       /* tag of next item */
2063                                 case 'T':       /* skip tag of next item */
2064                                 case 'v':       /* seq of strings */
2065                                 case 'V':       /* seq of strings + lengths */
2066                                 default:
2067                                         p_error = parse_bad_ber_format;
2068                                         break;
2069                         }
2070                         s++;
2071                 } else if (*s == ASTERIX_CHAR) {
2072                         fmt->type = mmt_any;
2073                         s++;
2074                         while (s < s_end && *s == ASTERIX_CHAR)
2075                                 s++;
2076 
2077                 } else if (*s == OPEN_BRACKET) {
2078                         escape = FALSE;
2079                         in_range = FALSE;
2080                         got_char = FALSE;
2081                         numRange = 0;
2082                         done = FALSE;
2083                         s++;
2084                         for (; s < s_end; s++) {
2085                                 if (escape) {
2086                                         escape = FALSE;
2087                                 } else if (*s == DASH_CHAR) {
2088                                         if (in_range || !got_char) {
2089                                                 p_error = parse_unexpected_dash;
2090                                                 break;
2091                                         }
2092                                         in_range = TRUE;
2093                                         got_char = FALSE;
2094                                         continue;
2095                                 } else if (*s == CLOSE_BRACKET) {
2096                                         if (in_range) {
2097                                                 p_error = parse_unexpected_dash;
2098                                         }
2099                                         done = TRUE;
2100                                         break;
2101                                 } else if (*s == ESCAPE_CHAR) {
2102                                         escape = TRUE;
2103                                         continue;
2104                                 }
2105                                 if (in_range) {
2106                                         hi[numRange - 1] = *s;
2107                                         in_range = FALSE;
2108                                 } else {
2109                                         lo = s_realloc(lo, numRange + 1);
2110                                         hi = s_realloc(hi, numRange + 1);
2111                                         if (lo == NULL || hi == NULL)
2112                                                 break;
2113                                         lo[numRange] = *s;
2114                                         hi[numRange] = *s;
2115                                         numRange++;
2116                                         got_char = TRUE;
2117                                 }
2118                         }
2119                         if (p_error != no_parse_error) {
2120                                 break;
2121                         } else if (!done) {
2122                                 p_error = parse_mismatched_brackets;
2123                                 break;
2124                         }
2125                         s++;
2126                         fmt->type = mmt_single;
2127                         fmt->match.single.numRange = numRange;
2128                         fmt->match.single.lo = (unsigned char *)lo;
2129                         fmt->match.single.hi = (unsigned char *)hi;
2130                 } else {
2131                         /* go to next key symbol - copy escaped key symbols */
2132                         escape = FALSE;
2133                         done = FALSE;
2134                         while (s < s_end) {
2135                                 if (escape)
2136                                         escape = FALSE;
2137                                 else {
2138                                     switch (*s) {
2139                                         case OPEN_BRACKET:
2140                                         case ASTERIX_CHAR:
2141                                         case PERCENT_SIGN:
2142                                                 done = TRUE;
2143                                                 break;
2144                                         case ESCAPE_CHAR:
2145                                                 escape = !escape;
2146                                                 break;
2147                                         default:
2148                                                 break;
2149                                     }
2150                                 }
2151                                 if (done)
2152                                         break;
2153                                 s++;
2154                         }
2155                         if (escape) {
2156                                 p_error = parse_unmatched_escape;
2157                                 break;
2158                         }
2159                         fmt->type = mmt_string;
2160                         fmt->match.string =
2161                                 s_strndup_esc(begin_fmt, s - begin_fmt);
2162                         if (fmt->match.string == NULL)
2163                                 break;
2164                 }
2165 
2166                 if (p_error == no_parse_error)
2167                         return (s);
2168         }
2169         if (lo != NULL)
2170                 free(lo);
2171         if (hi != NULL)
2172                 free(hi);
2173         return (NULL);
2174 }
2175 
2176 /*
2177  * FUNCTION:    get_next_print_format_item
2178  *
2179  *      Get the next format token from the string
2180  *
2181  * RETURN VALUE:        NULL if error
2182  *                      position of beginning next token after
2183  *                      token
2184  *
2185  * INPUT:               the format string
2186  */
2187 
2188 const char *
2189 get_next_print_format_item(
2190         const char              *begin_fmt,
2191         const char              *end_fmt,
2192         __nis_mapping_format_t  *fmt)
2193 {
2194         const char              *s      = begin_fmt;
2195         const char              *s_end  = end_fmt;
2196         bool_t                  skip_ber;
2197 
2198         for (; p_error == no_parse_error; ) {
2199                 if (s >= s_end) {
2200                         p_error = parse_internal_error;
2201                         break;
2202                 }
2203 
2204                 if (*s == PERCENT_SIGN) {
2205                         s++;
2206                         if (s >= s_end) {
2207                                 p_error = parse_unsupported_format;
2208                                 break;
2209                         }
2210                         skip_ber = FALSE;
2211                         /*
2212                          * If the format is %s, it is interpretted
2213                          * as a string.
2214                          */
2215                         switch (*s) {
2216                                 case 's':
2217                                         fmt->type = mmt_item;
2218                                         break;
2219                                 case 'n':       /* null */
2220                                 case 'x':       /* skip the next element */
2221                                         skip_ber = TRUE;
2222                                         /* FALLTHRU */
2223                                 case 'b':       /* boolean */
2224                                 case 'e':       /* enumerated */
2225                                 case 'i':       /* int */
2226                                 case 'o':       /* octet string */
2227                                 case 'B':       /* bit string */
2228                                         fmt->match.berString = s_strndup(s, 1);
2229                                         fmt->type = skip_ber ?
2230                                                 mmt_berstring_null :
2231                                                 mmt_berstring;
2232                                         break;
2233                                 case '{':       /* begin sequence */
2234                                 case '[':       /* begin set */
2235                                 case '}':       /* end sequence */
2236                                 case ']':       /* end set */
2237                                 case 'a':       /* octet string */
2238                                 case 'l':       /* length of next item */
2239                                 case 'O':       /* octet string */
2240                                 case 't':       /* tag of next item */
2241                                 case 'T':       /* skip tag of next item */
2242                                 case 'v':       /* seq of strings */
2243                                 case 'V':       /* seq of strings + lengths */
2244                                 default:
2245                                         p_error = parse_bad_ber_format;
2246                                         break;
2247                         }
2248                         s++;
2249                 } else {
2250                         while (s < s_end) {
2251                                 if (*s == PERCENT_SIGN)
2252                                         break;
2253                                 else if (*s == ESCAPE_CHAR)
2254                                         s++;
2255                                 s++;
2256                         }
2257                         if (s > s_end) {
2258                                 p_error = parse_unmatched_escape;
2259                                 break;
2260                         }
2261                         fmt->match.string =
2262                                 s_strndup_esc(begin_fmt, s - begin_fmt);
2263                         if (fmt->match.string == NULL)
2264                                 break;
2265                         fmt->type = mmt_string;
2266                 }
2267                 if (p_error == no_parse_error)
2268                         return (s);
2269         }
2270         return (NULL);
2271 }
2272 
2273 /*
2274  * FUNCTION:    get_ldap_filter
2275  *
2276  *      Gets an LDAP filter - see RFC 2254. Note that this does not
2277  *      determine if the ldap filter is valid. This only determines
2278  *      that the parentheses are balanced.
2279  *
2280  * RETURN VALUE:        NULL if error
2281  *                      position of beginning next token after
2282  *                      filter
2283  *
2284  * INPUT:               the begin and end of string
2285  *
2286  * OUTPUT:              the begin and end of LDAP filter
2287  *
2288  */
2289 
2290 const char *
2291 get_ldap_filter(const char **begin, const char **end)
2292 {
2293         const char      *s              = *begin;
2294         const char      *s_begin;
2295         const char      *s_end          = *end;
2296         int             nParen;
2297 
2298         for (; p_error == no_parse_error; ) {
2299                 while (s < s_end && is_whitespace(*s))
2300                         s++;
2301                 if (s == s_end) {
2302                         s = NULL;
2303                         break;
2304                 }
2305 
2306                 s_begin = s;
2307                 if (*s == OPEN_PAREN_CHAR) {
2308                         nParen = 1;
2309                         s++;
2310                         while (s < s_end && nParen > 0) {
2311                                 if (*s == ESCAPE_CHAR)
2312                                         s++;
2313                                 else if (*s == OPEN_PAREN_CHAR)
2314                                         nParen++;
2315                                 else if (*s == CLOSE_PAREN_CHAR)
2316                                         nParen--;
2317                                 s++;
2318                         }
2319                         if (nParen == 0) {
2320                                 *begin = s_begin;
2321                                 *end = s;
2322                                 while (s < s_end && is_whitespace(*s))
2323                                         s++;
2324                         } else
2325                                 s = NULL;
2326                 } else
2327                         s = NULL;
2328                 if (p_error == no_parse_error)
2329                         break;
2330         }
2331         if (s == NULL)
2332                 p_error = parse_invalid_ldap_search_filter;
2333 
2334         return (s);
2335 }
2336 
2337 /*
2338  * FUNCTION:    get_ava_list
2339  *
2340  *      Gets an attribute value assertion list
2341  *
2342  * RETURN VALUE:        NULL if error
2343  *                      position of beginning next token after
2344  *                      after attribute assertion
2345  *
2346  * INPUT:               the begin and end of string
2347  *                      Indicator if ava list is part of a nisplus
2348  *                      item
2349  *
2350  * OUTPUT:              the begin and end of LDAP filter
2351  *
2352  */
2353 
2354 const char *
2355 get_ava_list(const char **begin, const char **end, bool_t end_nisplus)
2356 {
2357         const char      *s              = *begin;
2358         const char      *s_begin;
2359         const char      *s_end          = *end;
2360         bool_t          in_quote;
2361         bool_t          got_equal;
2362         bool_t          got_data;
2363 
2364         for (; p_error == no_parse_error; ) {
2365                 while (s < s_end && is_whitespace(*s))
2366                         s++;
2367                 if (s == s_end) {
2368                         s = NULL;
2369                         break;
2370                 }
2371 
2372                 in_quote = FALSE;
2373                 got_equal = FALSE;
2374                 got_data = FALSE;
2375                 s_begin = s;
2376                 while (s < s_end) {
2377                         if (*s == ESCAPE_CHAR) {
2378                             s++;
2379                             got_data = TRUE;
2380                         } else if (*s == DOUBLE_QUOTE_CHAR) {
2381                             in_quote = !in_quote;
2382                             got_data = TRUE;
2383                         } else if (in_quote)
2384                                 ;
2385                         else if (*s == EQUAL_CHAR) {
2386                             if (end_nisplus && got_data && got_equal)
2387                                 break;
2388                             if (!got_data || got_equal) {
2389                                 got_equal = FALSE;
2390                                 break;
2391                             }
2392                             got_equal = TRUE;
2393                             got_data = FALSE;
2394                         } else if (*s == COMMA_CHAR) {
2395                             if (!got_data || !got_equal)
2396                                 break;
2397                             got_data = FALSE;
2398                             got_equal = FALSE;
2399                         } else if (is_whitespace(*s))
2400                                 ;
2401                         else
2402                                 got_data = TRUE;
2403                         s++;
2404                 }
2405                 if (!got_data || !got_equal || in_quote)
2406                         s = NULL;
2407                 else {
2408                         *begin = s_begin;
2409                         *end = s;
2410                         while (s < s_end && is_whitespace(*s))
2411                                 s++;
2412                 }
2413                 if (p_error == no_parse_error)
2414                         break;
2415         }
2416         if (s == NULL)
2417                 p_error = parse_invalid_ldap_search_filter;
2418 
2419         return (s);
2420 }
2421 
2422 /* Utility functions */
2423 bool_t
2424 validate_dn(const char *s, int len)
2425 {
2426         const char *end = s + len;
2427         bool_t  valid;
2428 
2429         valid = skip_get_dn(s, end) == end;
2430 
2431         if (!valid)
2432                 p_error = parse_bad_dn;
2433         return (valid);
2434 }
2435 
2436 bool_t
2437 validate_ldap_filter(const char *s, const char *end)
2438 {
2439         const char      *s_begin;
2440         const char      *s_end;
2441 
2442         s_begin = s;
2443         s_end = end;
2444 
2445         if (*s == OPEN_PAREN_CHAR) {
2446                 s = get_ldap_filter(&s_begin, &s_end);
2447         } else {
2448                 /* Assume an attribute value list */
2449                 s = get_ava_list(&s_begin, &s_end, FALSE);
2450         }
2451         if (s == NULL || s_end != end)
2452                 p_error = parse_invalid_ldap_search_filter;
2453 
2454         return (p_error == no_parse_error);
2455 }
2456 
2457 char *
2458 s_strndup(const char *s, int n)
2459 {
2460         char *d = (char *)malloc(n + 1);
2461 
2462         if (d != NULL) {
2463                 (void) memcpy(d, s, n);
2464                 d[n] = '\0';
2465         } else {
2466                 p_error = parse_no_mem_error;
2467         }
2468 
2469         return (d);
2470 }
2471 
2472 char *
2473 s_strndup_esc(const char *s, int n)
2474 {
2475         char    *d      = (char *)malloc(n + 1);
2476         int     i;
2477         int     j;
2478 
2479         if (d != NULL) {
2480                 for (i = 0, j = 0; i < n; i++) {
2481                         if (s[i] == ESCAPE_CHAR)
2482                                 i++;
2483                         d[j++] = s[i];
2484                 }
2485                 d[j] = '\0';
2486         } else {
2487                 p_error = parse_no_mem_error;
2488         }
2489 
2490         return (d);
2491 }
2492 
2493 void *
2494 s_calloc(size_t n, size_t size)
2495 {
2496         void *d = (char *)calloc(n, size);
2497 
2498         if (d == NULL) {
2499                 p_error = parse_no_mem_error;
2500         }
2501 
2502         return (d);
2503 }
2504 
2505 void *
2506 s_malloc(size_t size)
2507 {
2508         void *d = malloc(size);
2509         if (d == NULL)
2510                 p_error = parse_no_mem_error;
2511         return (d);
2512 }
2513 
2514 void *
2515 s_realloc(void *s, size_t size)
2516 {
2517         s = realloc(s, size);
2518         if (s == NULL)
2519                 p_error = parse_no_mem_error;
2520         return (s);
2521 }
2522 
2523 char *
2524 s_strdup(const char *s)
2525 {
2526         return (s != NULL ? s_strndup(s, strlen(s)) : NULL);
2527 }
2528 
2529 bool_t
2530 is_whitespace(int c)
2531 {
2532         return (c == ' ' || c == '\t');
2533 }
2534 
2535 bool_t
2536 is_string_ok(char *buffer, int buflen)
2537 {
2538         int i;
2539 
2540         if (buffer == NULL)
2541                 return (FALSE);
2542 
2543         for (i = 0; i < buflen; i++) {
2544                 if (!is_whitespace(buffer[i])) {
2545                         if (buffer[i] == POUND_SIGN)
2546                                 return (TRUE);
2547                         else
2548                                 return (FALSE);
2549                 }
2550         }
2551         return (TRUE);
2552 }
2553 
2554 /*
2555  * Returns true if the first string is contained at the beginning of the
2556  * second string. Otherwise returns false.
2557  */
2558 
2559 bool_t
2560 contains_string(const char *s1, const char *s2)
2561 {
2562         return (strncasecmp(s1, s2, strlen(s1)) == 0);
2563 }
2564 
2565 /*
2566  * Returns the next character position in the second string, if the first
2567  * string is contained at the beginning of the second string. Otherwise
2568  * returns NULL.
2569  */
2570 
2571 const char *
2572 skip_string(const char *s1, const char *s2, int len)
2573 {
2574         int len1 = strlen(s1);
2575 
2576         if (len >= len1 && strncasecmp(s1, s2, strlen(s1)) == 0)
2577                 return (s2 + len1);
2578         else
2579                 return (NULL);
2580 }
2581 
2582 /*
2583  * The second string is not necessarily null terminated.
2584  * same_string returns true if the second string matches the first.
2585  * Otherwise returns false.
2586  */
2587 
2588 bool_t
2589 same_string(const char *s1, const char *s2, int len)
2590 {
2591         int len1 = strlen(s1);
2592 
2593         return (len1 == len && strncasecmp(s1, s2, len1) == 0);
2594 }
2595 
2596 void
2597 report_error(const char *str, const char *attr)
2598 {
2599         char    fmt_buf[1024];
2600         int     pos             = 0;
2601 
2602         if (command_line_source != NULL) {
2603                 snprintf(fmt_buf, sizeof (fmt_buf), "Error parsing %s: ",
2604                         command_line_source);
2605                 pos = strlen(fmt_buf);
2606         } else if (file_source != NULL) {
2607                 snprintf(fmt_buf, sizeof (fmt_buf), "Error parsing file '%s': ",
2608                         file_source);
2609                 pos = strlen(fmt_buf);
2610         } else if (ldap_source != NULL) {
2611                 snprintf(fmt_buf, sizeof (fmt_buf), "Error for LDAP dn '%s': ",
2612                         ldap_source);
2613                 pos = strlen(fmt_buf);
2614         }
2615 
2616         if (start_line_num != 0) {
2617                 snprintf(fmt_buf + pos, sizeof (fmt_buf) - pos, "at line %d: ",
2618                         start_line_num);
2619                 pos += strlen(fmt_buf + pos);
2620         }
2621 
2622         if (attr != NULL) {
2623                 snprintf(fmt_buf + pos, sizeof (fmt_buf) - pos,
2624                         "for attribute %s: ", attr);
2625                 pos += strlen(fmt_buf + pos);
2626         }
2627 
2628         if (cons != NULL) {
2629                 snprintf(fmt_buf + pos, sizeof (fmt_buf) - pos, "%s\n",
2630                         parse_error_msg[p_error]);
2631                 fprintf(cons, fmt_buf, str == NULL ? "" : str);
2632         } else {
2633                 snprintf(fmt_buf + pos, sizeof (fmt_buf) - pos, "%s",
2634                         parse_error_msg[p_error]);
2635                 syslog(LOG_ERR, fmt_buf, str == NULL ? "" : str);
2636         }
2637 }
2638 
2639 void
2640 report_error2(
2641         const char      *str1,
2642         const char      *str2)
2643 {
2644         char    fmt_buf[1024];
2645 
2646         if (cons != NULL) {
2647                 snprintf(fmt_buf, sizeof (fmt_buf),
2648                         "%s\n",  parse_error_msg[p_error]);
2649                 fprintf(cons, fmt_buf, str1, str2);
2650         } else {
2651                 syslog(LOG_ERR, parse_error_msg[p_error], str1, str2);
2652         }
2653 }
2654 
2655 void
2656 report_conn_error(
2657         conn_error      e,
2658         const char      *str1,
2659         const char      *str2)
2660 {
2661         char    fmt_buf[1024];
2662 
2663         if (cons != NULL) {
2664                 snprintf(fmt_buf, sizeof (fmt_buf),
2665                         "%s\n",  conn_error_msg[e]);
2666                 fprintf(cons, fmt_buf,
2667                         str1 == NULL ? "" : str1,
2668                         str2 == NULL ? "" : str2);
2669         } else {
2670                 syslog(LOG_ERR,
2671                         conn_error_msg[e],
2672                         str1 == NULL ? "" : str1,
2673                         str2 == NULL ? "" : str2);
2674         }
2675 }
2676 
2677 void
2678 report_info(
2679         const char      *str,
2680         const char      *arg)
2681 {
2682         if (cons != NULL) {
2683                 fputs(str, cons);
2684                 if (arg != NULL)
2685                         fputs(arg, cons);
2686                 fputs("\n", cons);
2687         } else
2688                 syslog(LOG_INFO, str, arg);
2689 }