Home | History | Annotate | Download | only in libnisdb
      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 2005 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 <errno.h>
     35 #include <syslog.h>
     36 
     37 #include "ldap_parse.h"
     38 #include "nis_parse_ldap_conf.h"
     39 #include "nis_parse_ldap_err.h"
     40 #include "ldap_util.h"
     41 
     42 extern __nis_mapping_rule_t **dup_mapping_rules(
     43 	__nis_mapping_rule_t **rules, int n_rules);
     44 extern __nis_mapping_rule_t *dup_mapping_rule(
     45 	__nis_mapping_rule_t *in);
     46 
     47 static int	merge_table_mapping(__nis_table_mapping_t *in,
     48 	__nis_table_mapping_t *out);
     49 __nis_table_mapping_t *new_merged_mapping(const char *,
     50 	__nis_table_mapping_t *intbl);
     51 static int append_mapping_rule(__nis_mapping_rule_t *src_rule,
     52 	__nis_table_mapping_t *tbl, int flag);
     53 
     54 
     55 static int copy_object_dn(__nis_object_dn_t	*in,
     56 		__nis_object_dn_t	*newdn);
     57 
     58 /*
     59  * FUNCTION:	initialize_table_mapping
     60  *
     61  * Initialize the __nis_table_mapping_t structure.
     62  *
     63  * INPUT:	__nis_table_mapping_t
     64  *
     65  */
     66 void
     67 initialize_table_mapping(
     68 	__nis_table_mapping_t *mapping)
     69 {
     70 	if (mapping != NULL) {
     71 		mapping->dbId = NULL;
     72 
     73 		mapping->index.numIndexes = 0;
     74 		mapping->index.name = NULL;
     75 		mapping->index.value = NULL;
     76 
     77 		mapping->numColumns = 0;
     78 		mapping->column = NULL;
     79 
     80 		mapping->initTtlLo = (time_t)NO_VALUE_SET;
     81 		mapping->initTtlHi = (time_t)NO_VALUE_SET;
     82 		mapping->ttl = (time_t)NO_VALUE_SET;
     83 
     84 		mapping->usedns_flag = 0;
     85 		mapping->securemap_flag = 0;
     86 		mapping->commentChar = DEFAULT_COMMENT_CHAR;
     87 		mapping->numSplits = 0;
     88 
     89 		mapping->objectDN = NULL;
     90 
     91 		mapping->separatorStr = DEFAULT_SEP_STRING;
     92 
     93 		mapping->numRulesFromLDAP = 0;
     94 		mapping->numRulesToLDAP = 0;
     95 
     96 		mapping->ruleFromLDAP = NULL;
     97 		mapping->ruleToLDAP = NULL;
     98 
     99 		mapping->e = NULL;
    100 		mapping->objName = NULL;
    101 		mapping->objPath = NULL;
    102 		mapping->obj = NULL;
    103 		mapping->isMaster = 0;
    104 		mapping->seq_num = NO_VALUE_SET;
    105 	}
    106 }
    107 
    108 /*
    109  * FUNCTION:	initialize_yp_parse_structs
    110  *
    111  * Initialize the __yp_domain_context_t structure.
    112  *
    113  * INPUT:		__yp_domain_context_t
    114  *
    115  */
    116 void
    117 initialize_yp_parse_structs(
    118 	__yp_domain_context_t	*ypDomains)
    119 {
    120 	ypDomains->numDomains = 0;
    121 	ypDomains->domainLabels = NULL;
    122 	ypDomains->domains = NULL;
    123 	ypDomains->numYppasswdd = 0;
    124 	ypDomains->yppasswddDomainLabels = NULL;
    125 }
    126 
    127 /*
    128  * FUNCTION: 	merge_table_mapping
    129  *
    130  * Merges information from one table_mapping struct
    131  * into another
    132  *
    133  * INPUT: Source and Destination table_mapping structs.
    134  * RETURN: 0 on success and > 0 on error.
    135  */
    136 
    137 static int
    138 merge_table_mapping(
    139 	__nis_table_mapping_t *in,
    140 	__nis_table_mapping_t *out)
    141 {
    142 	int i;
    143 	int len;
    144 	int orig_num_rules;
    145 	int append;
    146 
    147 	if (in == NULL)
    148 		return (1);
    149 
    150 	if (in->dbId == NULL)
    151 		return (1);
    152 
    153 	/*
    154 	 * If 'in' is generic (non-expanded) and 'out' is domain-specific,
    155 	 * then rules from 'in' should not be appended to those in 'out'.
    156 	 */
    157 	if (!strchr(in->dbId, COMMA_CHAR) && strchr(out->dbId, COMMA_CHAR))
    158 		append = 0;
    159 	else
    160 		append = 1;
    161 
    162 
    163 	if (!out->index.numIndexes && in->index.numIndexes > 0) {
    164 		if (!dup_index(&in->index, &out->index))
    165 			return (1);
    166 	}
    167 
    168 	/* add_column() increments numColumns, so we don't */
    169 	if (!out->numColumns && in->numColumns > 0) {
    170 		for (i = 0; i < in->numColumns; i++) {
    171 			if (!add_column(out, in->column[i]))
    172 				return (1);
    173 		}
    174 	}
    175 
    176 	if (out->commentChar == DEFAULT_COMMENT_CHAR &&
    177 		in->commentChar != DEFAULT_COMMENT_CHAR)
    178 		out->commentChar = in->commentChar;
    179 
    180 	if (out->usedns_flag == 0)
    181 		out->usedns_flag = in->usedns_flag;
    182 
    183 	if (out->securemap_flag == 0)
    184 		out->securemap_flag = in->securemap_flag;
    185 
    186 	if (out->separatorStr == DEFAULT_SEP_STRING &&
    187 		in->separatorStr != DEFAULT_SEP_STRING) {
    188 		out->separatorStr = s_strdup(in->separatorStr);
    189 		if (!out->separatorStr)
    190 			return (2);
    191 	}
    192 
    193 	if (!out->numSplits && !out->e && in->e) {
    194 		out->numSplits = in->numSplits;
    195 		out->e = (__nis_mapping_element_t *)
    196 			s_calloc(1, (in->numSplits+1) *
    197 			sizeof (__nis_mapping_element_t));
    198 		if (!out->e)
    199 			return (2);
    200 		for (i = 0; i <= in->numSplits; i++) {
    201 			if (!dup_mapping_element(&in->e[i], &out->e[i])) {
    202 				for (; i > 0; i--) {
    203 					free_mapping_element(&out->e[i - 1]);
    204 				}
    205 				out->e = NULL;
    206 				return (1);
    207 			}
    208 		}
    209 	}
    210 
    211 	if (out->initTtlLo == (time_t)NO_VALUE_SET &&
    212 		in->initTtlLo != (time_t)NO_VALUE_SET)
    213 		out->initTtlLo = in->initTtlLo;
    214 
    215 	if (out->initTtlHi == (time_t)NO_VALUE_SET &&
    216 		in->initTtlHi != (time_t)NO_VALUE_SET)
    217 		out->initTtlHi = in->initTtlHi;
    218 
    219 	if (out->ttl == (time_t)NO_VALUE_SET &&
    220 		in->ttl != (time_t)NO_VALUE_SET)
    221 		out->ttl = in->ttl;
    222 
    223 	if (!out->numRulesFromLDAP && in->numRulesFromLDAP) {
    224 		out->ruleFromLDAP = dup_mapping_rules(in->ruleFromLDAP,
    225 			in->numRulesFromLDAP);
    226 		if (!out->ruleFromLDAP)
    227 			return (1);
    228 		out->numRulesFromLDAP = in->numRulesFromLDAP;
    229 	} else if (append && out->numRulesFromLDAP && in->numRulesFromLDAP) {
    230 		orig_num_rules = out->numRulesFromLDAP;
    231 		for (i = 0; i < in->numRulesFromLDAP; i++) {
    232 			if (append_mapping_rule(in->ruleFromLDAP[i], out, 0)) {
    233 				for (i = out->numRulesFromLDAP;
    234 					i > orig_num_rules; i--) {
    235 					free_mapping_rule(out->ruleFromLDAP[i]);
    236 					out->ruleFromLDAP[i] = NULL;
    237 				}
    238 				return (1);
    239 
    240 			}
    241 		}
    242 	}
    243 
    244 	if (!out->numRulesToLDAP && in->numRulesToLDAP) {
    245 		out->ruleToLDAP = dup_mapping_rules(in->ruleToLDAP,
    246 			in->numRulesToLDAP);
    247 		if (!out->ruleToLDAP)
    248 			return (1);
    249 		out->numRulesToLDAP = in->numRulesToLDAP;
    250 	} else if (append && out->numRulesToLDAP && in->numRulesToLDAP) {
    251 		orig_num_rules = out->numRulesToLDAP;
    252 		for (i = 0; i < in->numRulesToLDAP; i++) {
    253 			if (append_mapping_rule(in->ruleToLDAP[i], out, 1)) {
    254 				for (i = out->numRulesToLDAP;
    255 					i > orig_num_rules; i--) {
    256 					free_mapping_rule(out->ruleToLDAP[i]);
    257 					out->ruleToLDAP[i] = NULL;
    258 				}
    259 				return (1);
    260 			}
    261 		}
    262 	}
    263 	if (!out->objectDN && in->objectDN) {
    264 		out->objectDN = (__nis_object_dn_t *)
    265 			s_calloc(1, sizeof (__nis_object_dn_t));
    266 		if (!out->objectDN)
    267 			return (2);
    268 		if (copy_object_dn(in->objectDN, out->objectDN)) {
    269 			free_object_dn(out->objectDN);
    270 			out->objectDN = NULL;
    271 			return (1);
    272 		}
    273 	}
    274 
    275 	if (!out->objName && in->objName) {
    276 		if (!strchr(in->objName, SPACE_CHAR)) {
    277 		/* objName has no space- a single map dbIdMapping */
    278 			out->objName = s_strndup(in->objName,
    279 				strlen(in->objName));
    280 			if (!out->objName)
    281 				return (2);
    282 		}
    283 	}
    284 
    285 	if (!out->objName && out->dbId) {
    286 		out->objName = s_strndup(out->dbId, strlen(out->dbId));
    287 		if (!out->objName)
    288 			return (2);
    289 	}
    290 
    291 	if (out->seq_num == NO_VALUE_SET && in->seq_num >= 0)
    292 		out->seq_num = in->seq_num;
    293 
    294 	return (p_error == no_parse_error ? 0 : 1);
    295 }
    296 
    297 /*
    298  * FUNCTION:	copy_object_dn
    299  *
    300  * Copies a __nis_object_dn_t structure.
    301  *
    302  * RETURN:	0 on success, > 0 on failure.
    303  *
    304  * NOTE:	The caller MUST free newdn using
    305  *		free_object_dn() if return value != 0 (error condition)
    306  */
    307 
    308 static int
    309 copy_object_dn(
    310 	__nis_object_dn_t	*in,
    311 	__nis_object_dn_t	*newdn)
    312 {
    313 	if (in == NULL) {
    314 		p_error = parse_no_object_dn;
    315 		return (1);
    316 	}
    317 	while (in != NULL) {
    318 		if (in->read.base == NULL) {
    319 			newdn->read.base = NULL;
    320 		} else {
    321 			newdn->read.base = s_strndup(
    322 				in->read.base,
    323 				strlen(in->read.base));
    324 			if (newdn->read.base == NULL)
    325 				return (2);
    326 		}
    327 		newdn->read.scope = in->read.scope;
    328 		if (in->read.attrs) {
    329 			newdn->read.attrs = s_strndup(
    330 					in->read.attrs,
    331 					strlen(in->read.attrs));
    332 			if (newdn->read.attrs == NULL) {
    333 				return (2);
    334 			}
    335 		} else {
    336 			newdn->read.attrs = NULL;
    337 		}
    338 		newdn->read.element = in->read.element;
    339 		if (in->write.base != NULL) {
    340 			newdn->write.base = s_strndup(
    341 				in->write.base,
    342 				strlen(in->write.base));
    343 			if (newdn->write.base == NULL)
    344 				return (2);
    345 		} else {
    346 			newdn->write.base = NULL;
    347 		}
    348 		newdn->write.scope = in->write.scope;
    349 		if (in->write.attrs != NULL) {
    350 			newdn->write.attrs = s_strndup(
    351 				in->write.attrs,
    352 				strlen(in->write.attrs));
    353 			if (newdn->write.attrs == NULL) {
    354 				return (2);
    355 			}
    356 		} else {
    357 			newdn->write.attrs = NULL;
    358 		}
    359 		newdn->write.element = in->write.element;
    360 		if (in->dbIdName) {
    361 			newdn->dbIdName = s_strndup(in->dbIdName,
    362 						strlen(in->dbIdName));
    363 			if (newdn->dbIdName == NULL)
    364 				return (2);
    365 		}
    366 
    367 		if (in->delDisp)
    368 			newdn->delDisp = in->delDisp;
    369 
    370 		if (in->dbId && in->numDbIds > 0) {
    371 			newdn->dbId = dup_mapping_rules(in->dbId,
    372 					in->numDbIds);
    373 			if (!newdn->dbId)
    374 				return (1);
    375 			newdn->numDbIds = in->numDbIds;
    376 		}
    377 		if (in->next != NULL) {
    378 			newdn->next = (__nis_object_dn_t *)s_calloc(1,
    379 					sizeof (__nis_object_dn_t));
    380 			if (newdn->next == NULL)
    381 				return (1);
    382 			newdn = newdn->next;
    383 			in = in->next;
    384 		} else {
    385 			return (0);
    386 		}
    387 	} /* End of while on in */
    388 
    389 	return (0);
    390 }
    391 
    392 /*
    393  * FUNCTION:	free_yp_domain_context
    394  *
    395  * Frees __yp_domain_context_t
    396  *
    397  * INPUT:		__yp_domain_context_t
    398  */
    399 void
    400 free_yp_domain_context(__yp_domain_context_t *domains)
    401 {
    402 	int i;
    403 
    404 	if (domains != NULL) {
    405 		for (i = 0; i < domains->numDomains; i++) {
    406 			if (domains->domains[i] != NULL) {
    407 				free(domains->domains[i]);
    408 				domains->domains[i] = NULL;
    409 			}
    410 			if (domains->domainLabels[i] != NULL) {
    411 				free(domains->domainLabels[i]);
    412 				domains->domainLabels[i] = NULL;
    413 			}
    414 		}
    415 		domains->domains = NULL;
    416 		domains->domainLabels = NULL;
    417 		for (i = 0; i < domains->numYppasswdd; i++) {
    418 			if (domains->yppasswddDomainLabels[i] != NULL) {
    419 				free(domains->yppasswddDomainLabels[i]);
    420 				domains->yppasswddDomainLabels[i]
    421 					= NULL;
    422 			}
    423 		}
    424 		domains->yppasswddDomainLabels = NULL;
    425 		domains->numDomains = 0;
    426 		domains = NULL;
    427 	}
    428 }
    429 
    430 /*
    431  * FUNCTION:	second_parser_pass
    432  *
    433  * Prepares the linked list of table_mappings for processing
    434  * by finish_parse(), adding, merging and deleting structures
    435  * as necessary. Also adds dummy objectDN info. for splitField's.
    436  *
    437  * RETURN VALUE: 0 on success, > 0 on failure.
    438  */
    439 int
    440 second_parser_pass(
    441 	__nis_table_mapping_t   **table_mapping)
    442 {
    443 	__nis_table_mapping_t   *t, *t2;
    444 	__nis_table_mapping_t   *t_new = NULL, *tg;
    445 	__nis_table_mapping_t	*prev = NULL;
    446 	__nis_object_dn_t   *objectDN;
    447 	char	*objs, *dom;
    448 	char	*objName = NULL;
    449 	char	*lasts;
    450 	char	*tobj, *alias, *dupalias, *tmp;
    451 	char	*myself = "second_parser_pass";
    452 	int	i = 0, len;
    453 	int	remove_t = 0;
    454 	int	add_t = 0;
    455 
    456 	prev = NULL;
    457 	for (t = *table_mapping; t != NULL; ) {
    458 		/*
    459 		 * Temporarily using this field to flag deletion.
    460 		 * 0 : don't delete
    461 		 * 1 : delete
    462 		 * The mapping structure will be deleted in final_parser_pass
    463 		 */
    464 		t->isMaster = 0;
    465 
    466 		if (!t->dbId) {
    467 			p_error = parse_bad_map_error;
    468 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
    469 			"%s: no dbId field", myself);
    470 			return (1);
    471 		}
    472 		tg = NULL;
    473 		dom = strchr(t->dbId, COMMA_CHAR);
    474 		if (t->objName != NULL) {
    475 			objName = strdup(t->objName);
    476 			if (objName == NULL) {
    477 				p_error = parse_no_mem_error;
    478 				logmsg(MSG_NOMEM, LOG_ERR,
    479 		"%s: Cannot allocate memory for objName", myself);
    480 				return (1);
    481 			}
    482 			objs = (char *)strtok_r(objName, " ", &lasts);
    483 			/* Get the generic mapping */
    484 			if (dom != NULL) {
    485 				tg = find_table_mapping(t->dbId, dom - t->dbId,
    486 								*table_mapping);
    487 			}
    488 		} else {
    489 			objs = NULL;
    490 			if (dom == NULL) {
    491 				t->objName = s_strndup(t->dbId,
    492 						strlen(t->dbId));
    493 				if (!t->objName) {
    494 					logmsg(MSG_NOMEM, LOG_ERR,
    495 "%s: Cannot allocate memory for t->objName",
    496 						myself);
    497 					objs = NULL;
    498 					return (2);
    499 				}
    500 			} else {
    501 				/* Force relationship for domain specific */
    502 
    503 				/* Get the generic mapping */
    504 				tg = find_table_mapping(t->dbId, dom - t->dbId,
    505 								*table_mapping);
    506 				if (tg == NULL || tg->objName == NULL) {
    507 					/* If not found, use dbId for objName */
    508 					t->objName = s_strndup(t->dbId,
    509 							strlen(t->dbId));
    510 					if (t->objName == NULL) {
    511 						logmsg(MSG_NOMEM, LOG_ERR,
    512 "%s: Cannot allocate memory for t->objName",
    513 							myself);
    514 						return (2);
    515 					}
    516 				} else {
    517 					dom++;
    518 					tobj = s_strndup(tg->objName,
    519 							strlen(tg->objName));
    520 					if (tobj == NULL) {
    521 						logmsg(MSG_NOMEM, LOG_ERR,
    522 "%s: Cannot allocate memory for t->objName",
    523 							myself);
    524 						return (2);
    525 					}
    526 					alias = (char *)strtok_r(tobj, " ",
    527 									&lasts);
    528 
    529 					/* Loop 'breaks' on errors */
    530 					while (alias) {
    531 						tmp = NULL;
    532 						dupalias = s_strndup(alias,
    533 								strlen(alias));
    534 						if (!dupalias)
    535 							break;
    536 						if (getfullmapname(&dupalias,
    537 								dom)) {
    538 							i = 1;
    539 							break;
    540 						}
    541 						if (t->objName == NULL)
    542 							t->objName = dupalias;
    543 						else {
    544 							len = strlen(t->objName)
    545 							+ strlen(dupalias) + 2;
    546 							tmp = s_calloc(1, len);
    547 							if (tmp == NULL)
    548 								break;
    549 							snprintf(tmp, len,
    550 								"%s %s",
    551 								t->objName,
    552 								dupalias);
    553 							free(dupalias);
    554 							dupalias = NULL;
    555 							free(t->objName);
    556 							t->objName = tmp;
    557 						}
    558 						alias = (char *)strtok_r(NULL,
    559 								" ", &lasts);
    560 					}
    561 
    562 					if (tobj)
    563 						free(tobj);
    564 
    565 					if (alias ||
    566 						(objName = s_strdup(t->objName))
    567 								== NULL) {
    568 						if (i)
    569 							logmsg(MSG_NOTIMECHECK,
    570 							LOG_ERR,
    571 "%s: getfullmapname failed for %s for domain \"%s\"",
    572 							myself, dupalias, dom);
    573 						else {
    574 							p_error =
    575 							parse_no_mem_error;
    576 							logmsg(MSG_NOMEM,
    577 							LOG_ERR,
    578 "%s: Cannot allocate memory",
    579 							myself);
    580 						}
    581 						if (dupalias)
    582 							free(dupalias);
    583 						if (t->objName)
    584 							free(t->objName);
    585 						return (2);
    586 
    587 					}
    588 					objs = (char *)strtok_r(objName, " ",
    589 								&lasts);
    590 				}
    591 			}
    592 		}
    593 
    594 		if (tg != NULL) {
    595 			if (merge_table_mapping(tg, t)) {
    596 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
    597 "Error merging information from the %s to the %s mapping structure",
    598 					tg->dbId, t->dbId);
    599 				objs = NULL;
    600 				if (objName)
    601 					free(objName);
    602 				return (1);
    603 			}
    604 		}
    605 
    606 		/*
    607 		 * If objName is "map1 map2" then do the second pass.
    608 		 * If it is just "map1" however skip the expansion.
    609 		 * Also skip it if t->objName is null.
    610 		 */
    611 		if (objs && strncasecmp(objs, t->objName,
    612 			strlen(t->objName))) {
    613 			t2 = find_table_mapping(objs, strlen(objs),
    614 							*table_mapping);
    615 			if (t2) {
    616 				if (merge_table_mapping(t, t2)) {
    617 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
    618 "Error merging information from the %s to the %s mapping structure",
    619 						t->dbId, t2->dbId);
    620 					objs = NULL;
    621 					if (objName)
    622 						free(objName);
    623 					return (1);
    624 				}
    625 				t->isMaster = 1;
    626 			} else {
    627 				t_new = new_merged_mapping(objs, t);
    628 				if (t_new) {
    629 					t->isMaster = 1;
    630 					if (prev != NULL)
    631 						prev->next = t_new;
    632 					else
    633 						*table_mapping = t_new;
    634 					prev = t_new;
    635 					prev->next = t;
    636 				} else {
    637 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
    638 "Error creating a new mapping structure %s",
    639 						objs);
    640 					objs = NULL;
    641 					if (objName)
    642 						free(objName);
    643 					return (1);
    644 				}
    645 			}
    646 			while ((objs = (char *)strtok_r(NULL, " ", &lasts))
    647 				!= NULL) {
    648 				t2 = find_table_mapping(objs, strlen(objs),
    649 								*table_mapping);
    650 				if (t2) {
    651 					if (merge_table_mapping(t, t2)) {
    652 						logmsg(MSG_NOTIMECHECK, LOG_ERR,
    653 "Error merging information from the %s to the %s mapping structure",
    654 							t->dbId, t2->dbId);
    655 						objs = NULL;
    656 						if (objName)
    657 							free(objName);
    658 						return (1);
    659 					}
    660 					t->isMaster = 1;
    661 				} else {
    662 					/*
    663 					 * create a new t_map with dbId = objs
    664 					 * and copy t->* into new t_map
    665 					 */
    666 					t_new = new_merged_mapping(objs, t);
    667 					if (t_new) {
    668 						t->isMaster = 1;
    669 						if (prev != NULL)
    670 							prev->next = t_new;
    671 						else
    672 							*table_mapping = t_new;
    673 						prev = t_new;
    674 						prev->next = t;
    675 					} else {
    676 						logmsg(MSG_NOTIMECHECK, LOG_ERR,
    677 "Error creating a new mapping structure %s",
    678 							objs);
    679 						objs = NULL;
    680 						if (objName)
    681 							free(objName);
    682 						return (1);
    683 					}
    684 				}
    685 			}
    686 		} /* if objs!= NULL */
    687 
    688 		prev = t;
    689 		t = t->next;
    690 
    691 		if (objName) {
    692 			free(objName);
    693 			objName = NULL;
    694 			objs = NULL;
    695 		}
    696 	} /* for t = table_mapping loop */
    697 	return (0);
    698 }
    699 
    700 __nis_table_mapping_t *
    701 new_merged_mapping(const char *match,
    702 	__nis_table_mapping_t	*intbl)
    703 {
    704 
    705 	__nis_table_mapping_t	*outtable = NULL;
    706 
    707 	outtable = (__nis_table_mapping_t *)
    708 		s_calloc(1, sizeof (__nis_table_mapping_t));
    709 	if (outtable == NULL)
    710 		return (NULL);
    711 	initialize_table_mapping(outtable);
    712 	outtable->dbId = s_strndup(match, strlen(match));
    713 	if (outtable->dbId == NULL) {
    714 		free_table_mapping(outtable);
    715 		outtable = NULL;
    716 		return (NULL);
    717 	}
    718 	if (merge_table_mapping(intbl, outtable)) {
    719 		free_table_mapping(outtable);
    720 		outtable = NULL;
    721 	}
    722 	return (outtable);
    723 }
    724 
    725 /*
    726  * FUNCTION:	final_parser_pass
    727  *
    728  * completes the final expansion of t_map structures linked list.
    729  * all structures will have a non-null objPath as well as a objName
    730  * in the form of "mapname . domainname ." or "splitfieldname .
    731  * domainname .".
    732  *
    733  * RETURN VALUE:	0 on success, -1 on failure, -2 on fatal error.
    734  */
    735 int
    736 final_parser_pass(
    737 	__nis_table_mapping_t   **table_mapping,
    738 	__yp_domain_context_t   *ypDomains)
    739 {
    740 	__nis_table_mapping_t   *t;
    741 	__nis_table_mapping_t	*t1, *returned_map;
    742 	__nis_table_mapping_t   *prev = NULL;
    743 	int			i;
    744 	char			*myself = "final_parser_pass";
    745 	int			nm;
    746 	bool_t			r;
    747 	int			del_tbl_flag = 0;
    748 
    749 	if (ypDomains) {
    750 		if (!ypDomains->numDomains) {
    751 			p_error = parse_internal_error;
    752 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
    753 				"%s:No domains specified.", myself);
    754 			return (-1);
    755 		}
    756 	} else {
    757 		p_error = parse_internal_error;
    758 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
    759 				"%s:No domain structure supplied.", myself);
    760 		return (-1);
    761 	}
    762 	prev = NULL;
    763 
    764 	for (t = *table_mapping; t != NULL; ) {
    765 
    766 		/* Delete if marked for deletion by second_parser_pass */
    767 		if (t->isMaster == 1) {
    768 			if (prev != NULL)
    769 				prev->next = t->next;
    770 			else
    771 				*table_mapping = t->next;
    772 			t1 = t;
    773 			t = t->next;
    774 			free_table_mapping(t1);
    775 			continue;
    776 		}
    777 
    778 		if (!t->objName && t->dbId) {
    779 			t->objName = s_strndup(t->dbId, strlen(t->dbId));
    780 			if (!t->objName) {
    781 				logmsg(MSG_NOMEM, LOG_ERR,
    782 					"%s:Could not allocate.", myself);
    783 				return (-1);
    784 			}
    785 		}
    786 		i = ypDomains->numDomains;
    787 		while (i > 0) {
    788 			if (i == 1) {
    789 			/* modify existing table_mapping's */
    790 				nm = checkfullmapname(t->dbId,
    791 					ypDomains->domainLabels[0],
    792 					table_mapping, &returned_map);
    793 				if (nm == 1) {
    794 					/* delete this mapping structure */
    795 					logmsg(MSG_NOTIMECHECK,
    796 						LOG_WARNING,
    797 						"Mapping structure %s,%s "
    798 						"already exists.",
    799 						t->dbId,
    800 						ypDomains->domainLabels[0]);
    801 					if (merge_table_mapping(t,
    802 						returned_map)) {
    803 						logmsg(MSG_NOTIMECHECK, LOG_ERR,
    804 						    "Error merging information "
    805 						    "from the %s to the %s "
    806 						    "mapping structure.",
    807 						t->dbId, returned_map->dbId);
    808 						return (-1);
    809 					}
    810 					if (del_tbl_flag == 0)
    811 						del_tbl_flag = 1;
    812 				} else if (nm == -1) {
    813 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
    814 			"Error searching for %s,%s structure",
    815 					t->dbId, ypDomains->domainLabels[0]);
    816 					return (-1);
    817 				} else if (nm == 0 || nm == 2) {
    818 					if ((append_domainContext(&t,
    819 					ypDomains->domainLabels[0],
    820 					ypDomains->domains[0])) != 0) {
    821 						logmsg(MSG_NOTIMECHECK, LOG_ERR,
    822 					"Error appending domainContext %s",
    823 						ypDomains->domainLabels[0]);
    824 						return (-1);
    825 					}
    826 					del_tbl_flag = 0;
    827 				}
    828 			} else { /* if (i > 1) */
    829 				/* need to create new table_mapping's */
    830 				nm = checkfullmapname(t->dbId,
    831 					ypDomains->domainLabels[i - 1],
    832 					table_mapping, &returned_map);
    833 				if (nm == -1) {
    834 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
    835 				"Error searching for %s,%s structure",
    836 				t->dbId, ypDomains->domainLabels[i - 1]);
    837 					return (-1);
    838 				} else if (nm == 0) {
    839 					t1 = new_merged_mapping(t->dbId, t);
    840 					/* we clone ourselves */
    841 					if (t1) {
    842 						if ((append_domainContext(&t1,
    843 					ypDomains->domainLabels[i - 1],
    844 					ypDomains->domains[i - 1])) != 0) {
    845 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
    846 					"Error appending domainContext %s",
    847 					ypDomains->domainLabels[i - 1]);
    848 							free(t1);
    849 							return (-1);
    850 						}
    851 						if (prev != NULL) {
    852 							t1->next = prev->next;
    853 							prev->next = t1;
    854 							prev = prev->next;
    855 						} else {
    856 							t1->next =
    857 								*table_mapping;
    858 							*table_mapping = t1;
    859 							prev = t1;
    860 						}
    861 					} else { /* if !t1 */
    862 						p_error = parse_internal_error;
    863 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
    864 					"%s:Could not create new table -"
    865 					" check all instances of %s for errors",
    866 						myself, t->dbId);
    867 						return (-1);
    868 					}
    869 				} else if (nm == 1) {
    870 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
    871 				"Mapping structure %s,%s already exists.",
    872 						t->dbId,
    873 						ypDomains->domainLabels[i - 1]);
    874 					/*
    875 					 * We should be deleting this, but can't
    876 					 * really do it here, because we need to
    877 					 * match with the domainLabels[0] case
    878 					 * too. So we will just flag it for now.
    879 					 */
    880 					if (merge_table_mapping(t,
    881 						returned_map)) {
    882 						logmsg(MSG_NOTIMECHECK, LOG_ERR,
    883 	"Error merging information from the %s to the %s mapping structure.",
    884 							t->dbId,
    885 							returned_map->dbId);
    886 						return (-1);
    887 					}
    888 					del_tbl_flag = 1;
    889 				} else if (nm == 2) {
    890 					if ((append_domainContext(&t,
    891 						ypDomains->domainLabels[i - 1],
    892 						ypDomains->domains[i - 1]))
    893 						!= 0) {
    894 						logmsg(MSG_NOTIMECHECK, LOG_ERR,
    895 					"Error appending domainContext %s",
    896 						ypDomains->domainLabels[i - 1]);
    897 						return (-1);
    898 					}
    899 				} /* end of "if (nm == 0)" */
    900 			} /* end of else if (i > 1) */
    901 
    902 
    903 			/*
    904 			 * 'merge_table_mapping' only copies unexpanded
    905 			 * objectDN values into returned_map. Hence,
    906 			 * read.base and write.base in returned_map
    907 			 * needs to be expanded.
    908 			 */
    909 			if (nm == 1 && returned_map && returned_map->objectDN) {
    910 				r = make_fqdn(
    911 					returned_map->objectDN,
    912 					ypDomains->domains[i - 1]);
    913 				if (r == TRUE &&
    914 					returned_map->objectDN->write.base) {
    915 					r = make_full_dn(
    916 					&returned_map->objectDN->write.base,
    917 					ypDomains->domains[i - 1]);
    918 				}
    919 
    920 				if (r == FALSE) {
    921 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
    922 						"Error appending domainContext "
    923 						"%s to %s",
    924 						ypDomains->domainLabels[i - 1],
    925 						returned_map->dbId);
    926 					return (-2);
    927 				}
    928 			}
    929 			i--;
    930 		} /* end of while i > 0 loop */
    931 
    932 		if (del_tbl_flag == 1) {
    933 			if (prev != NULL) {
    934 				prev->next = t->next;
    935 				free_table_mapping(t);
    936 				t = prev->next;
    937 			} else {
    938 				*table_mapping = t->next;
    939 				free_table_mapping(t);
    940 				t = *table_mapping;
    941 			}
    942 			del_tbl_flag = 0;
    943 		} else {
    944 			prev = t;
    945 			t = t->next;
    946 		}
    947 	} /* end of table mapping loop */
    948 
    949 	for (t = *table_mapping; t != NULL; t = t->next) {
    950 		if (!t->dbId) {
    951 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
    952 				"%s:Fatal error: structure with no dbId found.",
    953 				myself);
    954 				return (-2);
    955 		}
    956 		append_dot(&t->dbId);
    957 		if (!t->objectDN) {
    958 			p_error = parse_internal_error;
    959 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
    960 				"%s:No objectDN for %s.", myself, t->dbId);
    961 			return (-1);
    962 		}
    963 	}
    964 
    965 	return (0);
    966 }
    967 
    968 /*
    969  * FUNCTION: append_mapping_rule
    970  *
    971  * Appends mapping rules to a table_mapping structure
    972  * with previously existing rules. flag controls whether
    973  * the functions works on the rules From or To LDAP.
    974  *
    975  * RETURN VALUE: 0 on success, >= 1 on failure.
    976  */
    977 
    978 static int
    979 append_mapping_rule(__nis_mapping_rule_t *src_rule,
    980 	__nis_table_mapping_t *dst, int flag)
    981 {
    982 	__nis_mapping_rule_t **rules = NULL;
    983 
    984 	if (flag == 0) {
    985 		if (dst->ruleFromLDAP == NULL) {
    986 			p_error = parse_internal_error;
    987 			return (1);
    988 		}
    989 		rules = (__nis_mapping_rule_t **)
    990 			s_realloc(dst->ruleFromLDAP,
    991 			(dst->numRulesFromLDAP + 1) *
    992 			sizeof (__nis_mapping_rule_t *));
    993 		if (rules == NULL)
    994 			return (2);
    995 		dst->ruleFromLDAP = rules;
    996 		rules[dst->numRulesFromLDAP] = dup_mapping_rule(src_rule);
    997 		if (rules[dst->numRulesFromLDAP] == NULL) {
    998 			p_error = parse_no_mem_error;
    999 			return (2);
   1000 		}
   1001 		dst->numRulesFromLDAP++;
   1002 	} else if (flag == 1) {
   1003 		if (dst->ruleToLDAP == NULL) {
   1004 			p_error = parse_internal_error;
   1005 			return (1);
   1006 		}
   1007 		rules = (__nis_mapping_rule_t **)
   1008 			s_realloc(dst->ruleToLDAP,
   1009 			(dst->numRulesToLDAP + 1) *
   1010 			sizeof (__nis_mapping_rule_t *));
   1011 		if (rules == NULL)
   1012 			return (2);
   1013 		dst->ruleToLDAP = rules;
   1014 		rules[dst->numRulesToLDAP] = dup_mapping_rule(src_rule);
   1015 		if (rules[dst->numRulesToLDAP] == NULL) {
   1016 			p_error = parse_no_mem_error;
   1017 			return (2);
   1018 		}
   1019 		dst->numRulesToLDAP++;
   1020 	} else
   1021 		return (1);
   1022 
   1023 	return (0);
   1024 }
   1025 
   1026 /*
   1027  * FUNCTION: check_domain_specific_order
   1028  *
   1029  * Makes sure that an attribute with explicitly specified
   1030  * nisLDAPdomainContext is found before its non-domain
   1031  * specific counterpart.
   1032  *
   1033  * RETURN VALUE: 0 normal exit
   1034  *               1 if domain specific attribute found
   1035  *                 after non-domain specific one.
   1036  *				 -1 some error condition
   1037  */
   1038 
   1039 int
   1040 check_domain_specific_order(const char *sd,
   1041 	config_key	attrib_num,
   1042 	__nis_table_mapping_t *table_mapping,
   1043 	__yp_domain_context_t   *ypDomains)
   1044 {
   1045 	__nis_table_mapping_t *t;
   1046 	char    *myself = "check_domain_specific_order";
   1047 	char	*type;
   1048 	char	*dbId = 0;
   1049 	int 	i, len;
   1050 	int		match = 0;
   1051 
   1052 	if (ypDomains) {
   1053 		if (!ypDomains->numDomains) {
   1054 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
   1055 				"%s:No domains specified.", myself);
   1056 			return (-1);
   1057 		}
   1058 	} else {
   1059 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
   1060 			"%s:No domain structure supplied.", myself);
   1061 		return (-1);
   1062 	}
   1063 
   1064 	for (i = 0; i < ypDomains->numDomains; i++) {
   1065 		for (t = table_mapping; t != NULL; t = t->next) {
   1066 			len = strlen(sd);
   1067 			if ((strcasecmp(t->dbId, sd) == 0) && (len ==
   1068 				strlen(t->dbId)))
   1069 				/* prevent from matching against itself */
   1070 				continue;
   1071 			dbId = s_strndup(t->dbId, strlen(t->dbId));
   1072 			if (dbId == NULL) {
   1073 				logmsg(MSG_NOMEM, LOG_ERR,
   1074 					"%s:Memory allocation error.", myself);
   1075 				return (-1);
   1076 			}
   1077 
   1078 			if (getfullmapname(&dbId,
   1079 				ypDomains->domainLabels[i])) {
   1080 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
   1081