xref: /illumos-gate/usr/src/lib/libnisdb/nis_parse_ldap_yp_util.c (revision f6e214c7418f43af38bd8c3a557e3d0a1d311cfa)
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 				"Error getting fully qualified name for %s",
1082 					dbId);
1083 				free(dbId);
1084 				return (-1);
1085 			}
1086 			if ((strcasecmp(dbId, sd) == 0) && (len ==
1087 				strlen(dbId))) {
1088 				match = 0;
1089 				switch (attrib_num) {
1090 					case key_yp_map_flags:
1091 						if (t->usedns_flag != 0 ||
1092 							t->securemap_flag != 0)
1093 							match = 1;
1094 						type = YP_MAP_FLAGS;
1095 						break;
1096 					case key_yp_comment_char:
1097 						if (t->commentChar !=
1098 							DEFAULT_COMMENT_CHAR)
1099 							match = 1;
1100 						type = YP_COMMENT_CHAR;
1101 						break;
1102 					case key_yp_repeated_field_separators:
1103 						if (t->separatorStr !=
1104 							DEFAULT_SEP_STRING)
1105 							match = 1;
1106 						type =
1107 					YP_REPEATED_FIELD_SEPARATORS;
1108 						break;
1109 					case key_yp_name_fields:
1110 						if (t->e && t->numColumns)
1111 							match = 1;
1112 						type = YP_NAME_FIELDS;
1113 					case key_yp_split_field:
1114 						if (t->e && t->numColumns)
1115 							match = 1;
1116 						type = YP_SPLIT_FIELD;
1117 						break;
1118 					case key_yp_db_id_map:
1119 						if (t->objName)
1120 							match = 1;
1121 						type = YP_DB_ID_MAP;
1122 						break;
1123 					case key_yp_entry_ttl:
1124 						if (t->initTtlLo !=
1125 							(time_t)NO_VALUE_SET)
1126 							match = 1;
1127 						type = YP_ENTRY_TTL;
1128 						break;
1129 					case key_yp_ldap_object_dn:
1130 						if (t->objectDN)
1131 							match = 1;
1132 						type = YP_LDAP_OBJECT_DN;
1133 						break;
1134 					case key_nis_to_ldap_map:
1135 						if (t->ruleToLDAP)
1136 							match = 1;
1137 						type = NIS_TO_LDAP_MAP;
1138 						break;
1139 					case key_ldap_to_nis_map:
1140 						if (t->ruleFromLDAP)
1141 							match = 1;
1142 						type = LDAP_TO_NIS_MAP;
1143 						break;
1144 					default:
1145 						type = "unknown";
1146 						match = 0;
1147 						break;
1148 				}	/* end of switch */
1149 				if (match) {
1150 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
1151 "Relative attribute '%s' of type '%s' found before fully qualified one '%s'",
1152 						t->dbId, type, sd);
1153 					free(dbId);
1154 					dbId = NULL;
1155 					return (1);
1156 				}
1157 			} /* end of strncasecmp */
1158 			free(dbId);
1159 			dbId = NULL;
1160 		} /* end of t loop */
1161 	} /* end of i loop */
1162 	if (dbId)
1163 		free(dbId);
1164 	dbId = NULL;
1165 	return (0);
1166 }
1167 
1168 int
1169 getfullmapname(char **mapname, const char *domainname)
1170 {
1171 	char *maps = *mapname;
1172 	int maplen = strlen(maps);
1173 	int domainlen = strlen(domainname);
1174 
1175 	if (!maplen || !domainlen ||
1176 		maps[maplen - 1] == PERIOD_CHAR)
1177 		return (1);
1178 	else if (strchr(maps, COMMA_CHAR)) {
1179 		/* map already has a domain part, do nothing */
1180 		return (0);
1181 	} else {
1182 		append_comma(&maps);
1183 		maplen = strlen(maps);
1184 		maps = realloc(maps, (maplen + domainlen + 1));
1185 		if (maps != NULL) {
1186 			if (strlcat(maps, domainname, (maplen + domainlen + 1))
1187 				>= (maplen + domainlen + 1))
1188 				return (1);
1189 			*mapname = maps;
1190 			return (0);
1191 		} else
1192 			return (1);
1193 	}
1194 }
1195 
1196 /*
1197  * FUNCTION: checkfullmapname
1198  *
1199  * Tries to find out if by appending the table mapping structures
1200  * with each of the provided nisLDAPdomainContexts, an already
1201  * existing fqdn table mapping structure results. That would be the
1202  * case when a full qualified domain specific attribute was present.
1203  *
1204  * Note that per NISLDAPmapping(4) such an attribute MUST be listed
1205  * in the mapping file BEFORE its non-fqdn counterpart.
1206  *
1207  * RETURNS:	0 normal exit, 1 if an existing structure found, -1 for all
1208  * errors, 2 if already fqdn. If returning 1 the existing structure is
1209  * in found_map.
1210  */
1211 
1212 int
1213 checkfullmapname(const char *mapname, const char *domainname,
1214 __nis_table_mapping_t **table_mapping,
1215 __nis_table_mapping_t **found_map)
1216 {
1217 	char *map;
1218 
1219 	*found_map = NULL;
1220 
1221 	/* This function does not alter mapname */
1222 
1223 	if (!mapname || !domainname || *table_mapping == NULL)
1224 		return (-1);
1225 
1226 	if (strchr(mapname, COMMA_CHAR))
1227 		return (2);
1228 
1229 	if ((map = s_strndup(mapname, strlen(mapname))) == 0)
1230 		return (-1);
1231 
1232 	if (getfullmapname(&map, domainname)) {
1233 		free(map);
1234 		return (-1);
1235 	}
1236 
1237 	*found_map = find_table_mapping(map, strlen(map), *table_mapping);
1238 	if (*found_map) {
1239 		free(map);
1240 		return (1);
1241 	}
1242 
1243 	free(map);
1244 	return (0);
1245 }
1246 
1247 /*
1248  * FUNCTION:	append_domainContext
1249  *
1250  * Higher level function to append the domains to the appropriate
1251  * fields in a table mapping structure. Calls either getfullmapname()
1252  * or make_full_dn() to do the actual append.
1253  *
1254  * RETURNS: 0 on success, -1 on any error.
1255  */
1256 
1257 int
1258 append_domainContext(__nis_table_mapping_t **table_map,
1259 char   *DomainLabel, char *Domain)
1260 {
1261 	__nis_table_mapping_t *tmp_map = *table_map;
1262 	char *lasts;
1263 	char *tmp_dbId = NULL;
1264 	char *id = NULL;
1265 	int  domain_specific = 0;
1266 	char *myself = "append_domainContext";
1267 
1268 	if (!DomainLabel || !Domain || !tmp_map)
1269 		return (-1);
1270 	if (tmp_map->dbId == NULL || tmp_map->objName == NULL) {
1271 		p_error = parse_bad_map_error;
1272 		return (-1);
1273 	}
1274 	tmp_dbId = s_strndup(tmp_map->dbId, strlen(tmp_map->dbId));
1275 	if (!tmp_dbId)
1276 		return (-1);
1277 	if (strchr(tmp_map->dbId, COMMA_CHAR)) {
1278 		domain_specific = 1;
1279 		id = (char *)strtok_r(tmp_dbId, COMMA_STRING, &lasts);
1280 		if (id)
1281 			id = (char *)strtok_r(NULL, COMMA_STRING, &lasts);
1282 		else {
1283 			free(tmp_dbId);
1284 			return (-1);
1285 		}
1286 		if (!id) {
1287 			free(tmp_dbId);
1288 			return (-1);
1289 		}
1290 		if (strcasecmp(id, DomainLabel)) {
1291 			free(tmp_dbId);
1292 			return (0);
1293 		}
1294 	} else {
1295 		if (getfullmapname(&tmp_map->dbId, DomainLabel)) {
1296 			free(tmp_dbId);
1297 			return (-1);
1298 		}
1299 		append_dot(&tmp_map->dbId);
1300 	}
1301 	if (tmp_dbId)
1302 		free(tmp_dbId);
1303 	tmp_dbId = NULL;
1304 
1305 	if (getfullmapname(&tmp_map->objName, DomainLabel))
1306 		return (-1);
1307 	append_dot(&tmp_map->objName);
1308 
1309 	/*
1310 	 * If domain specific mapping doesn't have objectDN,
1311 	 * then don't touch. Most probably, pass for the generic mapping
1312 	 * will handle this by coping over it's own objectDN
1313 	 */
1314 	if (domain_specific && tmp_map->objectDN == NULL)
1315 		return (0);
1316 
1317 	if (tmp_map->objectDN == NULL) {
1318 		/* Allocate memory to objectDN */
1319 		tmp_map->objectDN = (__nis_object_dn_t *)
1320 			s_calloc(1, sizeof (__nis_object_dn_t));
1321 		if (tmp_map->objectDN == NULL) {
1322 			logmsg(MSG_NOMEM, LOG_ERR,
1323 "%s: Cannot allocate memory for objectDN",
1324 				myself);
1325 			return (2);
1326 		}
1327 		tmp_map->objectDN->read.base = NULL;
1328 		tmp_map->objectDN->write.base = NULL;
1329 		tmp_map->objectDN->read.attrs = NULL;
1330 		tmp_map->objectDN->write.attrs = NULL;
1331 		tmp_map->objectDN->read.scope = LDAP_SCOPE_ONELEVEL;
1332 		tmp_map->objectDN->write.scope = LDAP_SCOPE_UNKNOWN;
1333 	}
1334 
1335 	if (!make_fqdn(tmp_map->objectDN, Domain))
1336 		return (-1);
1337 	if (tmp_map->objectDN->write.base) {
1338 		if (!make_full_dn(&tmp_map->objectDN->write.base, Domain))
1339 			return (-1);
1340 	}
1341 
1342 	return (0);
1343 }
1344