xref: /onnv-gate/usr/src/lib/libnisdb/yptol/dit_access_utils.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * DESCRIPTION:	Contains dit_access interface support functions.
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate #include <sys/systeminfo.h>
33*0Sstevel@tonic-gate #include <unistd.h>
34*0Sstevel@tonic-gate #include <stdlib.h>
35*0Sstevel@tonic-gate #include <sys/types.h>
36*0Sstevel@tonic-gate #include <sys/stat.h>
37*0Sstevel@tonic-gate #include <sys/systeminfo.h>
38*0Sstevel@tonic-gate #include <unistd.h>
39*0Sstevel@tonic-gate #include <stdlib.h>
40*0Sstevel@tonic-gate #include <syslog.h>
41*0Sstevel@tonic-gate #include <ndbm.h>
42*0Sstevel@tonic-gate #include <strings.h>
43*0Sstevel@tonic-gate #include <errno.h>
44*0Sstevel@tonic-gate #include "../ldap_util.h"
45*0Sstevel@tonic-gate #include "../ldap_map.h"
46*0Sstevel@tonic-gate #include "../ldap_parse.h"
47*0Sstevel@tonic-gate #include "../ldap_structs.h"
48*0Sstevel@tonic-gate #include "../ldap_val.h"
49*0Sstevel@tonic-gate #include "../ldap_ruleval.h"
50*0Sstevel@tonic-gate #include "../ldap_op.h"
51*0Sstevel@tonic-gate #include "../ldap_attr.h"
52*0Sstevel@tonic-gate #include "../ldap_nisdbquery.h"
53*0Sstevel@tonic-gate #include "../nisdb_mt.h"
54*0Sstevel@tonic-gate #include "shim.h"
55*0Sstevel@tonic-gate #include "yptol.h"
56*0Sstevel@tonic-gate #include "dit_access_utils.h"
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate /*
59*0Sstevel@tonic-gate  * Returns 'map,domain.'
60*0Sstevel@tonic-gate  */
61*0Sstevel@tonic-gate char *
62*0Sstevel@tonic-gate getFullMapName(char *map, char *domain) {
63*0Sstevel@tonic-gate 	char	*myself = "getFullMapName";
64*0Sstevel@tonic-gate 	char	*objPath;
65*0Sstevel@tonic-gate 	if (map == 0 || domain == 0) {
66*0Sstevel@tonic-gate 		return (0);
67*0Sstevel@tonic-gate 	}
68*0Sstevel@tonic-gate 	objPath =  scat(myself, T, scat(myself, F, map, ","),
69*0Sstevel@tonic-gate 		scat(myself, F, domain, "."));
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 	return (objPath);
72*0Sstevel@tonic-gate }
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate /*
75*0Sstevel@tonic-gate  * Convert string to __nis_value_t
76*0Sstevel@tonic-gate  */
77*0Sstevel@tonic-gate __nis_value_t *stringToValue(char *dptr, int dsize) {
78*0Sstevel@tonic-gate 	char		*myself = "stringToValue";
79*0Sstevel@tonic-gate 	char		*emptystr = "";
80*0Sstevel@tonic-gate 	__nis_value_t	*val;
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	if ((val = am(myself, sizeof (*val))) == 0) {
83*0Sstevel@tonic-gate 		return (0);
84*0Sstevel@tonic-gate 	}
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	val->type = vt_string;
87*0Sstevel@tonic-gate 	val->repeat = 0;
88*0Sstevel@tonic-gate 	val->numVals = 1;
89*0Sstevel@tonic-gate 	if ((val->val = am(myself, sizeof (val->val[0]))) == 0) {
90*0Sstevel@tonic-gate 		sfree(val);
91*0Sstevel@tonic-gate 		return (0);
92*0Sstevel@tonic-gate 	}
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 	/*
95*0Sstevel@tonic-gate 	 * Null strings or strings with length 0 are treated
96*0Sstevel@tonic-gate 	 * as empty strings with length 1
97*0Sstevel@tonic-gate 	 */
98*0Sstevel@tonic-gate 	if (dptr == 0 || dsize <= 0) {
99*0Sstevel@tonic-gate 		dptr = emptystr;
100*0Sstevel@tonic-gate 		dsize = 1;
101*0Sstevel@tonic-gate 	}
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	val->val->length = dsize;
104*0Sstevel@tonic-gate 	if (dptr[dsize - 1] != '\0') {
105*0Sstevel@tonic-gate 		val->val->length = dsize + 1;
106*0Sstevel@tonic-gate 	}
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate 	val->val->value = am(myself, val->val->length);
109*0Sstevel@tonic-gate 	if (val->val->value == 0) {
110*0Sstevel@tonic-gate 		freeValue(val, 1);
111*0Sstevel@tonic-gate 		return (0);
112*0Sstevel@tonic-gate 	}
113*0Sstevel@tonic-gate 	(void) memcpy(val->val->value, dptr, dsize);
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	return (val);
116*0Sstevel@tonic-gate }
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate /*
119*0Sstevel@tonic-gate  * Returns an array of rule-values corresponding to the
120*0Sstevel@tonic-gate  * splitfields.
121*0Sstevel@tonic-gate  */
122*0Sstevel@tonic-gate __nis_rule_value_t *
123*0Sstevel@tonic-gate processSplitField(__nis_table_mapping_t *sf, __nis_value_t *inVal,
124*0Sstevel@tonic-gate 			int *nv, int *statP) {
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	char			*sepset;
127*0Sstevel@tonic-gate 	__nis_rule_value_t	*rvq;
128*0Sstevel@tonic-gate 	__nis_mapping_format_t  *ftmp;
129*0Sstevel@tonic-gate 	__nis_value_t		**valA, *tempVal;
130*0Sstevel@tonic-gate 	int			i, j, res, numVals, oldlen, count;
131*0Sstevel@tonic-gate 	char			*str, *oldstr;
132*0Sstevel@tonic-gate 	char			*myself = "processSplitField";
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 	/* sf will be non NULL */
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	if (inVal == 0 || inVal->type != vt_string) {
137*0Sstevel@tonic-gate 		*statP =  MAP_PARAM_ERROR;
138*0Sstevel@tonic-gate 		return (0);
139*0Sstevel@tonic-gate 	}
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	/* Get the separator list */
142*0Sstevel@tonic-gate 	sepset = sf->separatorStr;
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	/* Initialize rule-value */
145*0Sstevel@tonic-gate 	rvq = 0;
146*0Sstevel@tonic-gate 	count = 0;
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate 	if ((tempVal = stringToValue(inVal->val->value,
149*0Sstevel@tonic-gate 			inVal->val->length)) == 0) {
150*0Sstevel@tonic-gate 		*statP = MAP_NO_MEMORY;
151*0Sstevel@tonic-gate 		return (0);
152*0Sstevel@tonic-gate 	}
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	str = oldstr = tempVal->val->value;
155*0Sstevel@tonic-gate 	oldlen = tempVal->val->length;
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	while (str) {
158*0Sstevel@tonic-gate 		tempVal->val->value = str;
159*0Sstevel@tonic-gate 		tempVal->val->length = strlen(str) + 1;
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 		/* Loop to check which format matches str */
162*0Sstevel@tonic-gate 		for (i = 0; i <= sf->numSplits; i++) {
163*0Sstevel@tonic-gate 			valA = matchMappingItem(sf->e[i].element.match.fmt,
164*0Sstevel@tonic-gate 				tempVal, &numVals, sepset, &str);
165*0Sstevel@tonic-gate 			if (valA == 0) {
166*0Sstevel@tonic-gate 				/* The format didn't match. Try the next one */
167*0Sstevel@tonic-gate 				continue;
168*0Sstevel@tonic-gate 			}
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate 			/*
171*0Sstevel@tonic-gate 			 * If we are here means we had a match.
172*0Sstevel@tonic-gate 			 * Each new set of values obtained from the match is
173*0Sstevel@tonic-gate 			 * added to a new rule-value. This is to preserve the
174*0Sstevel@tonic-gate 			 * the distinction between each set.
175*0Sstevel@tonic-gate 			 */
176*0Sstevel@tonic-gate 			rvq = growRuleValue(count, count + 1, rvq, 0);
177*0Sstevel@tonic-gate 			if (rvq == 0) {
178*0Sstevel@tonic-gate 				*statP = MAP_INTERNAL_ERROR;
179*0Sstevel@tonic-gate 				for (j = 0; j < numVals; j++)
180*0Sstevel@tonic-gate 					freeValue(valA[j], 1);
181*0Sstevel@tonic-gate 				sfree(valA);
182*0Sstevel@tonic-gate 				tempVal->val->value = oldstr;
183*0Sstevel@tonic-gate 				tempVal->val->length = oldlen;
184*0Sstevel@tonic-gate 				freeValue(tempVal, 1);
185*0Sstevel@tonic-gate 				return (0);
186*0Sstevel@tonic-gate 			}
187*0Sstevel@tonic-gate 			count++;
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 			for (j = 0; j < numVals; j++) {
190*0Sstevel@tonic-gate 				res = addCol2RuleValue(vt_string,
191*0Sstevel@tonic-gate 					sf->e[i].element.match.item[j].name,
192*0Sstevel@tonic-gate 					valA[j]->val->value,
193*0Sstevel@tonic-gate 					valA[j]->val->length,
194*0Sstevel@tonic-gate 					&rvq[count - 1]);
195*0Sstevel@tonic-gate 				if (res == -1) {
196*0Sstevel@tonic-gate 					*statP = MAP_INTERNAL_ERROR;
197*0Sstevel@tonic-gate 					for (; j < numVals; j++)
198*0Sstevel@tonic-gate 						freeValue(valA[j], 1);
199*0Sstevel@tonic-gate 					sfree(valA);
200*0Sstevel@tonic-gate 					tempVal->val->value = oldstr;
201*0Sstevel@tonic-gate 					tempVal->val->length = oldlen;
202*0Sstevel@tonic-gate 					freeValue(tempVal, 1);
203*0Sstevel@tonic-gate 					freeRuleValue(rvq, count);
204*0Sstevel@tonic-gate 					return (0);
205*0Sstevel@tonic-gate 				}
206*0Sstevel@tonic-gate 				freeValue(valA[j], 1);
207*0Sstevel@tonic-gate 			}
208*0Sstevel@tonic-gate 			sfree(valA);
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 			/*
211*0Sstevel@tonic-gate 			 * Since we had a match, break out of this loop
212*0Sstevel@tonic-gate 			 * to parse remainder of str
213*0Sstevel@tonic-gate 			 */
214*0Sstevel@tonic-gate 			break;
215*0Sstevel@tonic-gate 		}
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 		/* Didn't find any match, so get out of the loop */
218*0Sstevel@tonic-gate 		if (i > sf->numSplits) {
219*0Sstevel@tonic-gate 			str = 0;
220*0Sstevel@tonic-gate 			break;
221*0Sstevel@tonic-gate 		}
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 		/* Skip the separators before looping back */
224*0Sstevel@tonic-gate 		if (str) {
225*0Sstevel@tonic-gate 			str = str + strspn(str, sepset);
226*0Sstevel@tonic-gate 			if (*str == '\0')
227*0Sstevel@tonic-gate 				break;
228*0Sstevel@tonic-gate 		}
229*0Sstevel@tonic-gate 	}
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	tempVal->val->value = oldstr;
232*0Sstevel@tonic-gate 	tempVal->val->length = oldlen;
233*0Sstevel@tonic-gate 	freeValue(tempVal, 1);
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	if (str == 0) {
236*0Sstevel@tonic-gate 		freeRuleValue(rvq, count);
237*0Sstevel@tonic-gate 		return (0);
238*0Sstevel@tonic-gate 	}
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	if (nv != 0)
241*0Sstevel@tonic-gate 		*nv = count;
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	return (rvq);
244*0Sstevel@tonic-gate }
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate /*
247*0Sstevel@tonic-gate  * Convert the datum to an array of RuleValues
248*0Sstevel@tonic-gate  */
249*0Sstevel@tonic-gate __nis_rule_value_t *
250*0Sstevel@tonic-gate datumToRuleValue(datum *key, datum *value, __nis_table_mapping_t *t,
251*0Sstevel@tonic-gate 			int *nv, char *domain, bool_t readonly, int *statP) {
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	__nis_rule_value_t	*rvq, *subrvq, *newrvq;
254*0Sstevel@tonic-gate 	__nis_value_t		*val;
255*0Sstevel@tonic-gate 	__nis_value_t		**valA;
256*0Sstevel@tonic-gate 	__nis_table_mapping_t	*sf;
257*0Sstevel@tonic-gate 	int			valueLen, comLen, numVals, nr, count = 1;
258*0Sstevel@tonic-gate 	int			i, j, k, l, af;
259*0Sstevel@tonic-gate 	char			*ipaddr, *ipvalue;
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	/*  At this point, 't' is always non NULL */
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	/* Initialize rule-value */
264*0Sstevel@tonic-gate 	if ((rvq = initRuleValue(1, 0)) == 0) {
265*0Sstevel@tonic-gate 		*statP = MAP_INTERNAL_ERROR;
266*0Sstevel@tonic-gate 		return (0);
267*0Sstevel@tonic-gate 	}
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	/* Add domainname to rule-value */
270*0Sstevel@tonic-gate 	if (addCol2RuleValue(vt_string, N2LDOMAIN, domain, strlen(domain),
271*0Sstevel@tonic-gate 						rvq)) {
272*0Sstevel@tonic-gate 		freeRuleValue(rvq, 1);
273*0Sstevel@tonic-gate 		*statP = MAP_INTERNAL_ERROR;
274*0Sstevel@tonic-gate 		return (0);
275*0Sstevel@tonic-gate 	}
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	/* Handle key */
278*0Sstevel@tonic-gate 	if (key != 0) {
279*0Sstevel@tonic-gate 		/* Add field=value pair for N2LKEY */
280*0Sstevel@tonic-gate 		i = addCol2RuleValue(vt_string, N2LKEY, key->dptr, key->dsize,
281*0Sstevel@tonic-gate 						rvq);
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 		/* For readonly, add field=value pair for N2LSEARCHKEY */
284*0Sstevel@tonic-gate 		if (readonly == TRUE && i == 0) {
285*0Sstevel@tonic-gate 			i = addCol2RuleValue(vt_string, N2LSEARCHKEY, key->dptr,
286*0Sstevel@tonic-gate 						key->dsize, rvq);
287*0Sstevel@tonic-gate 		}
288*0Sstevel@tonic-gate 		if (i) {
289*0Sstevel@tonic-gate 			freeRuleValue(rvq, 1);
290*0Sstevel@tonic-gate 			*statP = MAP_INTERNAL_ERROR;
291*0Sstevel@tonic-gate 			return (0);
292*0Sstevel@tonic-gate 		}
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 		/* Add field=value pairs for IP addresses */
295*0Sstevel@tonic-gate 		if (checkIPaddress(key->dptr, key->dsize, &ipaddr) > 0) {
296*0Sstevel@tonic-gate 			/* If key is IPaddress, use preferred format */
297*0Sstevel@tonic-gate 			ipvalue = ipaddr;
298*0Sstevel@tonic-gate 			valueLen = strlen(ipaddr);
299*0Sstevel@tonic-gate 			i = addCol2RuleValue(vt_string, N2LIPKEY, ipvalue,
300*0Sstevel@tonic-gate 						valueLen, rvq);
301*0Sstevel@tonic-gate 		} else {
302*0Sstevel@tonic-gate 			/* If not, use original value for N2LSEARCHIPKEY */
303*0Sstevel@tonic-gate 			ipaddr = 0;
304*0Sstevel@tonic-gate 			ipvalue = key->dptr;
305*0Sstevel@tonic-gate 			valueLen = key->dsize;
306*0Sstevel@tonic-gate 			i = 0;
307*0Sstevel@tonic-gate 		}
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 		if (readonly == TRUE && i == 0) {
310*0Sstevel@tonic-gate 			i = addCol2RuleValue(vt_string, N2LSEARCHIPKEY, ipvalue,
311*0Sstevel@tonic-gate 								valueLen, rvq);
312*0Sstevel@tonic-gate 		}
313*0Sstevel@tonic-gate 		sfree(ipaddr);
314*0Sstevel@tonic-gate 		if (i) {
315*0Sstevel@tonic-gate 			freeRuleValue(rvq, 1);
316*0Sstevel@tonic-gate 			*statP = MAP_INTERNAL_ERROR;
317*0Sstevel@tonic-gate 			return (0);
318*0Sstevel@tonic-gate 		}
319*0Sstevel@tonic-gate 	}
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	/* Handle datum value */
322*0Sstevel@tonic-gate 	if (value != 0 && t->e) {
323*0Sstevel@tonic-gate 		valueLen = value->dsize;
324*0Sstevel@tonic-gate 		/*
325*0Sstevel@tonic-gate 		 * Extract the comment, if any, and add it to
326*0Sstevel@tonic-gate 		 * the rule-value.
327*0Sstevel@tonic-gate 		 */
328*0Sstevel@tonic-gate 		if (t->commentChar != '\0') {
329*0Sstevel@tonic-gate 			/*
330*0Sstevel@tonic-gate 			 * We loop on value->dsize because value->dptr
331*0Sstevel@tonic-gate 			 * may not be NULL-terminated.
332*0Sstevel@tonic-gate 			 */
333*0Sstevel@tonic-gate 			for (i = 0; i < value->dsize; i++) {
334*0Sstevel@tonic-gate 				if (value->dptr[i] == t->commentChar) {
335*0Sstevel@tonic-gate 					valueLen = i;
336*0Sstevel@tonic-gate 					comLen = value->dsize - i - 1;
337*0Sstevel@tonic-gate 					if (comLen == 0)
338*0Sstevel@tonic-gate 						break;
339*0Sstevel@tonic-gate 					if (addCol2RuleValue(vt_string,
340*0Sstevel@tonic-gate 						N2LCOMMENT, value->dptr + i + 1,
341*0Sstevel@tonic-gate 						comLen, rvq)) {
342*0Sstevel@tonic-gate 						freeRuleValue(rvq, 1);
343*0Sstevel@tonic-gate 						*statP = MAP_INTERNAL_ERROR;
344*0Sstevel@tonic-gate 						return (0);
345*0Sstevel@tonic-gate 					}
346*0Sstevel@tonic-gate 					break;
347*0Sstevel@tonic-gate 				}
348*0Sstevel@tonic-gate 			}
349*0Sstevel@tonic-gate 		}
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 		/* Skip trailing whitespaces */
352*0Sstevel@tonic-gate 		for (; valueLen > 0 && (value->dptr[valueLen - 1] == ' ' ||
353*0Sstevel@tonic-gate 			value->dptr[valueLen - 1] == '\t'); valueLen--);
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 		/*
356*0Sstevel@tonic-gate 		 * At this point valueLen is the effective length of
357*0Sstevel@tonic-gate 		 * the data. Convert value into __nis_value_t so that
358*0Sstevel@tonic-gate 		 * we can use the matchMappingItem function to break it
359*0Sstevel@tonic-gate 		 * into fields.
360*0Sstevel@tonic-gate 		 */
361*0Sstevel@tonic-gate 		if ((val = stringToValue(value->dptr, valueLen)) == 0) {
362*0Sstevel@tonic-gate 			freeRuleValue(rvq, 1);
363*0Sstevel@tonic-gate 			*statP = MAP_NO_MEMORY;
364*0Sstevel@tonic-gate 			return (0);
365*0Sstevel@tonic-gate 		}
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 		/* Perform namefield match */
368*0Sstevel@tonic-gate 		valA = matchMappingItem(t->e->element.match.fmt, val,
369*0Sstevel@tonic-gate 							&numVals, 0, 0);
370*0Sstevel@tonic-gate 		if (valA == 0) {
371*0Sstevel@tonic-gate 			freeValue(val, 1);
372*0Sstevel@tonic-gate 			freeRuleValue(rvq, 1);
373*0Sstevel@tonic-gate 			*statP = MAP_NAMEFIELD_MATCH_ERROR;
374*0Sstevel@tonic-gate 			return (0);
375*0Sstevel@tonic-gate 		}
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 		/* We don't need val anymore, so free it */
378*0Sstevel@tonic-gate 		freeValue(val, 1);
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 		/*
381*0Sstevel@tonic-gate 		 * Since matchMappingItem only returns us an array of
382*0Sstevel@tonic-gate 		 * __nis_value_t's, we need to associate each value
383*0Sstevel@tonic-gate 		 * in the array with the corresponding item name.
384*0Sstevel@tonic-gate 		 * This code assumes that numVals will be less than or
385*0Sstevel@tonic-gate 		 * equal to the number of item names associated with
386*0Sstevel@tonic-gate 		 * the format.
387*0Sstevel@tonic-gate 		 * These name=value pairs are added to rvq.
388*0Sstevel@tonic-gate 		 */
389*0Sstevel@tonic-gate 		for (i = 0, *statP = SUCCESS; i < numVals; i++) {
390*0Sstevel@tonic-gate 			for (j = 0; j < count; j++) {
391*0Sstevel@tonic-gate 				if (addCol2RuleValue(vt_string,
392*0Sstevel@tonic-gate 					t->e->element.match.item[i].name,
393*0Sstevel@tonic-gate 					valA[i]->val->value,
394*0Sstevel@tonic-gate 					valA[i]->val->length, &rvq[j])) {
395*0Sstevel@tonic-gate 					*statP = MAP_INTERNAL_ERROR;
396*0Sstevel@tonic-gate 					break;
397*0Sstevel@tonic-gate 				}
398*0Sstevel@tonic-gate 			}
399*0Sstevel@tonic-gate 			if (*statP == MAP_INTERNAL_ERROR)
400*0Sstevel@tonic-gate 				break;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 			/*
403*0Sstevel@tonic-gate 			 * Check if splitField exists for the field.
404*0Sstevel@tonic-gate 			 * Since splitfields are also stored as mapping
405*0Sstevel@tonic-gate 			 * structures, we need to get the hash table entry
406*0Sstevel@tonic-gate 			 * corresponding to the splitfield name
407*0Sstevel@tonic-gate 			 */
408*0Sstevel@tonic-gate 			sf = mappingFromMap(t->e->element.match.item[i].name,
409*0Sstevel@tonic-gate 					domain, statP);
410*0Sstevel@tonic-gate 			if (*statP == MAP_NO_MEMORY)
411*0Sstevel@tonic-gate 				break;
412*0Sstevel@tonic-gate 			*statP = SUCCESS;
413*0Sstevel@tonic-gate 			if (sf == 0)
414*0Sstevel@tonic-gate 				continue;
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 			/*
417*0Sstevel@tonic-gate 			 * Process and add splitFields to rule-value rvq
418*0Sstevel@tonic-gate 			 */
419*0Sstevel@tonic-gate 			subrvq = processSplitField(sf, valA[i], &nr, statP);
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 			if (subrvq == 0) {
422*0Sstevel@tonic-gate 				/* statP would have been set */
423*0Sstevel@tonic-gate 				break;
424*0Sstevel@tonic-gate 			}
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 			/*
427*0Sstevel@tonic-gate 			 * We merge 'count' rule-values in rvq with 'nr'
428*0Sstevel@tonic-gate 			 * rule-values from subrvq to give us a whopping
429*0Sstevel@tonic-gate 			 * 'count * nr' rule-values
430*0Sstevel@tonic-gate 			 */
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 			/* Initialize the new rule-value array */
433*0Sstevel@tonic-gate 			if ((newrvq = initRuleValue(count * nr, 0)) == 0) {
434*0Sstevel@tonic-gate 				*statP = MAP_INTERNAL_ERROR;
435*0Sstevel@tonic-gate 				freeRuleValue(subrvq, nr);
436*0Sstevel@tonic-gate 				break;
437*0Sstevel@tonic-gate 			}
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 			for (j = 0, l = 0; j < nr; j++) {
440*0Sstevel@tonic-gate 				for (k = 0; k < count; k++, l++) {
441*0Sstevel@tonic-gate 					if ((mergeRuleValue(&newrvq[l],
442*0Sstevel@tonic-gate 							&rvq[k]) == -1) ||
443*0Sstevel@tonic-gate 							(mergeRuleValue(
444*0Sstevel@tonic-gate 							&newrvq[l],
445*0Sstevel@tonic-gate 							&subrvq[j]) == -1)) {
446*0Sstevel@tonic-gate 						*statP = MAP_INTERNAL_ERROR;
447*0Sstevel@tonic-gate 						for (i = 0; i < numVals; i++)
448*0Sstevel@tonic-gate 							freeValue(valA[i], 1);
449*0Sstevel@tonic-gate 						sfree(valA);
450*0Sstevel@tonic-gate 						freeRuleValue(rvq, count);
451*0Sstevel@tonic-gate 						freeRuleValue(newrvq,
452*0Sstevel@tonic-gate 								count * nr);
453*0Sstevel@tonic-gate 						freeRuleValue(subrvq, nr);
454*0Sstevel@tonic-gate 						return (0);
455*0Sstevel@tonic-gate 					}
456*0Sstevel@tonic-gate 				}
457*0Sstevel@tonic-gate 			}
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 			freeRuleValue(rvq, count);
460*0Sstevel@tonic-gate 			rvq = newrvq;
461*0Sstevel@tonic-gate 			count = l;
462*0Sstevel@tonic-gate 			freeRuleValue(subrvq, nr);
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 		}
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 		/* We don't need valA anymore, so free it */
467*0Sstevel@tonic-gate 		for (i = 0; i < numVals; i++)
468*0Sstevel@tonic-gate 			freeValue(valA[i], 1);
469*0Sstevel@tonic-gate 		sfree(valA);
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 		if (*statP != SUCCESS) {
472*0Sstevel@tonic-gate 			freeRuleValue(rvq, count);
473*0Sstevel@tonic-gate 			return (0);
474*0Sstevel@tonic-gate 		}
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 	} /* if value */
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	if (nv != 0)
479*0Sstevel@tonic-gate 		*nv = count;
480*0Sstevel@tonic-gate 	return (rvq);
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate }
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate /*
485*0Sstevel@tonic-gate  * Generate name=values pairs for splitfield names
486*0Sstevel@tonic-gate  *
487*0Sstevel@tonic-gate  * Consider Example:
488*0Sstevel@tonic-gate  *	nisLDAPnameFields club:
489*0Sstevel@tonic-gate  *			("%s %s %s", name, code, members)
490*0Sstevel@tonic-gate  *	nisLDAPsplitField members:
491*0Sstevel@tonic-gate  *			("(%s,%s,%s)", host, user, domain),
492*0Sstevel@tonic-gate  *			("%s", group)
493*0Sstevel@tonic-gate  * On entry,
494*0Sstevel@tonic-gate  * - rv is an array of numVals rule-values each containing
495*0Sstevel@tonic-gate  * name=value pairs for names occuring in nisLDAPsplitField.
496*0Sstevel@tonic-gate  * (i.e host, user, domain, group)
497*0Sstevel@tonic-gate  * - trv contains name=value pairs for names occuring in
498*0Sstevel@tonic-gate  * nisLDAPnameFields. (i.e name, code but not members)
499*0Sstevel@tonic-gate  *
500*0Sstevel@tonic-gate  * For every name in nisLDAPnamefields that is a splitfield,
501*0Sstevel@tonic-gate  * this function applies the data in rv to the corresponding
502*0Sstevel@tonic-gate  * splitfield formats (accessed thru t), to generate a single
503*0Sstevel@tonic-gate  * string value for the corresponding splitfield (members).
504*0Sstevel@tonic-gate  * This new name=value pair is then added to trv.
505*0Sstevel@tonic-gate  * Besides, any uninitialized namefield names are set to empty strings.
506*0Sstevel@tonic-gate  */
507*0Sstevel@tonic-gate suc_code
508*0Sstevel@tonic-gate addSplitFieldValues(__nis_table_mapping_t *t, __nis_rule_value_t *rv,
509*0Sstevel@tonic-gate 			__nis_rule_value_t *trv, int numVals, char *domain) {
510*0Sstevel@tonic-gate 	__nis_table_mapping_t	*sf;
511*0Sstevel@tonic-gate 	__nis_value_t		*val;
512*0Sstevel@tonic-gate 	int			i, j, k, nitems, res, statP;
513*0Sstevel@tonic-gate 	char			*str, *tempstr;
514*0Sstevel@tonic-gate 	char			delim[2] = {0, 0};
515*0Sstevel@tonic-gate 	char			*emptystr = "";
516*0Sstevel@tonic-gate 	char			*myself = "addSplitFieldValues";
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	if (trv == 0)
519*0Sstevel@tonic-gate 		return (MAP_INTERNAL_ERROR);
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 	if (t->e == 0)
522*0Sstevel@tonic-gate 		return (SUCCESS);
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 	nitems = t->e->element.match.numItems;
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate 	/*
527*0Sstevel@tonic-gate 	 * Procedure:
528*0Sstevel@tonic-gate 	 * - Check each name in nisLDAPnamefield
529*0Sstevel@tonic-gate 	 * - if it's a splifield, construct its value and add it to trv
530*0Sstevel@tonic-gate 	 * - if not, check if it has a value
531*0Sstevel@tonic-gate 	 * - if not, add empty string
532*0Sstevel@tonic-gate 	 */
533*0Sstevel@tonic-gate 	for (i = 0, sf = 0; i < nitems; i++) {
534*0Sstevel@tonic-gate 		if (rv) {
535*0Sstevel@tonic-gate 			/*
536*0Sstevel@tonic-gate 			 * str will eventually contain the single string
537*0Sstevel@tonic-gate 			 * value for the corresponding  splitfield.
538*0Sstevel@tonic-gate 			 * No point initializing str if rv == 0 because
539*0Sstevel@tonic-gate 			 * splitfield cannot be constructed without rv.
540*0Sstevel@tonic-gate 			 * So, only initialized here.
541*0Sstevel@tonic-gate 			 */
542*0Sstevel@tonic-gate 			str = 0;
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 			/* Check if it's a splitfield name */
545*0Sstevel@tonic-gate 			sf = mappingFromMap(t->e->element.match.item[i].name,
546*0Sstevel@tonic-gate 				domain, &statP);
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 			/*
549*0Sstevel@tonic-gate 			 * Return only incase of memory allocation failure.
550*0Sstevel@tonic-gate 			 * The other error case (MAP_NO_MAPPING_EXISTS),
551*0Sstevel@tonic-gate 			 * indicates that the item name is not a splitfieldname
552*0Sstevel@tonic-gate 			 * i.e it's a namefieldname. This case is handled by
553*0Sstevel@tonic-gate 			 * the following if (sf == 0)
554*0Sstevel@tonic-gate 			 */
555*0Sstevel@tonic-gate 			if (statP == MAP_NO_MEMORY)
556*0Sstevel@tonic-gate 				return (statP);
557*0Sstevel@tonic-gate 		}
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 		if (sf == 0) {
560*0Sstevel@tonic-gate 			/*
561*0Sstevel@tonic-gate 			 * Not a splitfield name. Verify if it has a value
562*0Sstevel@tonic-gate 			 */
563*0Sstevel@tonic-gate 			if (findVal(t->e->element.match.item[i].name,
564*0Sstevel@tonic-gate 				trv, mit_nisplus) == 0) {
565*0Sstevel@tonic-gate 				/* if not, use empty string */
566*0Sstevel@tonic-gate 				res = addCol2RuleValue(vt_string,
567*0Sstevel@tonic-gate 					t->e->element.match.item[i].name,
568*0Sstevel@tonic-gate 					emptystr, 0, trv);
569*0Sstevel@tonic-gate 				if (res == -1) {
570*0Sstevel@tonic-gate 					return (MAP_INTERNAL_ERROR);
571*0Sstevel@tonic-gate 				}
572*0Sstevel@tonic-gate 			}
573*0Sstevel@tonic-gate 			/*
574*0Sstevel@tonic-gate 			 * If rv == 0 then sf == 0 so we will continue here
575*0Sstevel@tonic-gate 			 * i.e. does not matter that str is not yet set up.
576*0Sstevel@tonic-gate 			 */
577*0Sstevel@tonic-gate 			continue;
578*0Sstevel@tonic-gate 		}
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 		/* Code to construct a single value */
581*0Sstevel@tonic-gate 
582*0Sstevel@tonic-gate 		/* Use the first separator character as the delimiter */
583*0Sstevel@tonic-gate 		delim[0] = sf->separatorStr[0];
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 		for (j = 0; j < numVals; j++) {
586*0Sstevel@tonic-gate 			/* sf->numSplits is zero-based */
587*0Sstevel@tonic-gate 			for (k = 0; k <= sf->numSplits; k++) {
588*0Sstevel@tonic-gate 				val = getMappingFormatArray(
589*0Sstevel@tonic-gate 					sf->e[k].element.match.fmt, &rv[j],
590*0Sstevel@tonic-gate 					fa_item,
591*0Sstevel@tonic-gate 					sf->e[k].element.match.numItems,
592*0Sstevel@tonic-gate 					sf->e[k].element.match.item);
593*0Sstevel@tonic-gate 				if (val == 0)
594*0Sstevel@tonic-gate 					continue;
595*0Sstevel@tonic-gate 				if (val->numVals > 0) {
596*0Sstevel@tonic-gate 					if (str) {
597*0Sstevel@tonic-gate 						tempstr = scat(myself,
598*0Sstevel@tonic-gate 							0, str, delim);
599*0Sstevel@tonic-gate 						sfree(str);
600*0Sstevel@tonic-gate 						if (tempstr)
601*0Sstevel@tonic-gate 							str = tempstr;
602*0Sstevel@tonic-gate 						else {
603*0Sstevel@tonic-gate 							freeValue(val, 1);
604*0Sstevel@tonic-gate 							return (MAP_NO_MEMORY);
605*0Sstevel@tonic-gate 						}
606*0Sstevel@tonic-gate 					}
607*0Sstevel@tonic-gate 					tempstr = scat(myself, 0, str,
608*0Sstevel@tonic-gate 						val->val->value);
609*0Sstevel@tonic-gate 					sfree(str);
610*0Sstevel@tonic-gate 					if (tempstr)
611*0Sstevel@tonic-gate 						str = tempstr;
612*0Sstevel@tonic-gate 					else {
613*0Sstevel@tonic-gate 						freeValue(val, 1);
614*0Sstevel@tonic-gate 						return (MAP_NO_MEMORY);
615*0Sstevel@tonic-gate 					}
616*0Sstevel@tonic-gate 				}
617*0Sstevel@tonic-gate 				freeValue(val, 1);
618*0Sstevel@tonic-gate 			}
619*0Sstevel@tonic-gate 		}
620*0Sstevel@tonic-gate 		if (str == 0)
621*0Sstevel@tonic-gate 			str = emptystr;
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 		res = addCol2RuleValue(vt_string,
624*0Sstevel@tonic-gate 				t->e->element.match.item[i].name,
625*0Sstevel@tonic-gate 				str, strlen(str), trv);
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 		if (str != emptystr)
628*0Sstevel@tonic-gate 			sfree(str);
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 		if (res == -1) {
631*0Sstevel@tonic-gate 			return (MAP_INTERNAL_ERROR);
632*0Sstevel@tonic-gate 		}
633*0Sstevel@tonic-gate 	}
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 	return (SUCCESS);
636*0Sstevel@tonic-gate }
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate /*
639*0Sstevel@tonic-gate  * Updates 'rv' with NIS name=value pairs suitable to
640*0Sstevel@tonic-gate  * construct datum from namefield information.
641*0Sstevel@tonic-gate  * Some part based on createNisPlusEntry (from ldap_nisdbquery.c)
642*0Sstevel@tonic-gate  * This code assumes that from a given LDAP entry, applying the
643*0Sstevel@tonic-gate  * mapping rules, would give us one or more NIS entries, differing
644*0Sstevel@tonic-gate  * only in key.
645*0Sstevel@tonic-gate  */
646*0Sstevel@tonic-gate suc_code
647*0Sstevel@tonic-gate buildNISRuleValue(__nis_table_mapping_t *t, __nis_rule_value_t *rv,
648*0Sstevel@tonic-gate 					char *domain) {
649*0Sstevel@tonic-gate 	int			r, i, j, k, l, index, nrq, res, len;
650*0Sstevel@tonic-gate 	int			numItems, splitname, count, statP;
651*0Sstevel@tonic-gate 	__nis_value_t		*rval;
652*0Sstevel@tonic-gate 	__nis_mapping_item_t	*litem;
653*0Sstevel@tonic-gate 	__nis_mapping_rule_t	*rl;
654*0Sstevel@tonic-gate 	__nis_rule_value_t	*rvq;
655*0Sstevel@tonic-gate 	char			*value, *emptystr = "";
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	statP = SUCCESS;
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	/* Initialize default base */
660*0Sstevel@tonic-gate 	__nisdb_get_tsd()->searchBase = t->objectDN->read.base;
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	/* Initialize rule-value rvq */
663*0Sstevel@tonic-gate 	rvq = 0;
664*0Sstevel@tonic-gate 	count = 0;
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 	/* Add domainname to rule-value */
667*0Sstevel@tonic-gate 	if (addCol2RuleValue(vt_string, N2LDOMAIN, domain, strlen(domain),
668*0Sstevel@tonic-gate 						rv)) {
669*0Sstevel@tonic-gate 		return (MAP_INTERNAL_ERROR);
670*0Sstevel@tonic-gate 	}
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 	for (r = 0; r < t->numRulesFromLDAP; r++) {
673*0Sstevel@tonic-gate 		rl = t->ruleFromLDAP[r];
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 		/* Set escapeFlag if RHS is "dn" to remove escape chars */
676*0Sstevel@tonic-gate 		if (rl->rhs.numElements == 1 &&
677*0Sstevel@tonic-gate 			rl->rhs.element->type == me_item &&
678*0Sstevel@tonic-gate 			rl->rhs.element->element.item.type == mit_ldap &&
679*0Sstevel@tonic-gate 			strcasecmp(rl->rhs.element->element.item.name, "dn")
680*0Sstevel@tonic-gate 									== 0) {
681*0Sstevel@tonic-gate 				__nisdb_get_tsd()->escapeFlag = '2';
682*0Sstevel@tonic-gate 		}
683*0Sstevel@tonic-gate 
684*0Sstevel@tonic-gate 		rval = buildRvalue(&rl->rhs, mit_ldap, rv, NULL);
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 		/* Reset escapeFlag */
687*0Sstevel@tonic-gate 		__nisdb_get_tsd()->escapeFlag = '\0';
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate 		if (rval == 0) {
690*0Sstevel@tonic-gate 			continue;
691*0Sstevel@tonic-gate 		}
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 		if (rval->numVals <= 0) {
694*0Sstevel@tonic-gate 			/* Treat as invalid */
695*0Sstevel@tonic-gate 			freeValue(rval, 1);
696*0Sstevel@tonic-gate 			continue;
697*0Sstevel@tonic-gate 		}
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 		litem = buildLvalue(&rl->lhs, &rval, &numItems);
700*0Sstevel@tonic-gate 		if (litem == 0) {
701*0Sstevel@tonic-gate 			/* This will take care of numItems == 0 */
702*0Sstevel@tonic-gate 			freeValue(rval, 1);
703*0Sstevel@tonic-gate 			continue;
704*0Sstevel@tonic-gate 		}
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 		if (rval->numVals > 1) {
707*0Sstevel@tonic-gate 			if (numItems == 1 && litem->repeat)
708*0Sstevel@tonic-gate 				nrq = rval->numVals;
709*0Sstevel@tonic-gate 			else if (numItems > 1 && rval->repeat)
710*0Sstevel@tonic-gate 				nrq = 1 + ((rval->numVals-1)/numItems);
711*0Sstevel@tonic-gate 			else
712*0Sstevel@tonic-gate 				nrq = 1;
713*0Sstevel@tonic-gate 		} else
714*0Sstevel@tonic-gate 			nrq = 1;
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 		/* Set splitname if splitfield names are specified */
717*0Sstevel@tonic-gate 		for (i = 0; i < numItems; i++) {
718*0Sstevel@tonic-gate 			if (strcasecmp(litem[i].name, N2LKEY) == 0 ||
719*0Sstevel@tonic-gate 				strcasecmp(litem[i].name, N2LIPKEY) == 0 ||
720*0Sstevel@tonic-gate 				strcasecmp(litem[i].name, N2LCOMMENT) == 0)
721*0Sstevel@tonic-gate 				continue;
722*0Sstevel@tonic-gate 			for (j = 0; j < t->numColumns; j++) {
723*0Sstevel@tonic-gate 				if (strcmp(litem[i].name, t->column[j]) == 0)
724*0Sstevel@tonic-gate 					break;
725*0Sstevel@tonic-gate 			}
726*0Sstevel@tonic-gate 			if (j == t->numColumns)
727*0Sstevel@tonic-gate 				break;
728*0Sstevel@tonic-gate 		}
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 		splitname = (i < numItems)?1:0;
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 		for (j = 0; j < nrq; j++) {
733*0Sstevel@tonic-gate 			if (splitname == 1) {
734*0Sstevel@tonic-gate 				/*
735*0Sstevel@tonic-gate 				 * Put every value of splitfieldname in a new
736*0Sstevel@tonic-gate 				 * rule-value. Helps generating splitfields.
737*0Sstevel@tonic-gate 				 */
738*0Sstevel@tonic-gate 				rvq = growRuleValue(count, count + 1, rvq, 0);
739*0Sstevel@tonic-gate 				if (rvq == 0) {
740*0Sstevel@tonic-gate 					freeRuleValue(rvq, count);
741*0Sstevel@tonic-gate 					freeValue(rval, 1);
742*0Sstevel@tonic-gate 					freeMappingItem(litem, numItems);
743*0Sstevel@tonic-gate 					return (MAP_INTERNAL_ERROR);
744*0Sstevel@tonic-gate 				}
745*0Sstevel@tonic-gate 				count++;
746*0Sstevel@tonic-gate 			}
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate 			for (k = j % nrq, l = 0; l < numItems; k += nrq, l++) {
749*0Sstevel@tonic-gate 				/* If we run out of values, use empty strings */
750*0Sstevel@tonic-gate 				if (k >= rval->numVals) {
751*0Sstevel@tonic-gate 					value = emptystr;
752*0Sstevel@tonic-gate 					len = 0;
753*0Sstevel@tonic-gate 				} else {
754*0Sstevel@tonic-gate 					value = rval->val[k].value;
755*0Sstevel@tonic-gate 					len = rval->val[k].length;
756*0Sstevel@tonic-gate 				}
757*0Sstevel@tonic-gate 				res = (splitname == 1)?addCol2RuleValue(
758*0Sstevel@tonic-gate 					vt_string, litem[l].name, value,
759*0Sstevel@tonic-gate 					len, &rvq[count - 1]):0;
760*0Sstevel@tonic-gate 				if (res != -1)
761*0Sstevel@tonic-gate 					res = addCol2RuleValue(vt_string,
762*0Sstevel@tonic-gate 						litem[l].name, value, len, rv);
763*0Sstevel@tonic-gate 				if (res == -1) {
764*0Sstevel@tonic-gate 					freeRuleValue(rvq, count);
765*0Sstevel@tonic-gate 					freeValue(rval, 1);
766*0Sstevel@tonic-gate 					freeMappingItem(litem, numItems);
767*0Sstevel@tonic-gate 					return (MAP_INTERNAL_ERROR);
768*0Sstevel@tonic-gate 				}
769*0Sstevel@tonic-gate 			}
770*0Sstevel@tonic-gate 		}
771*0Sstevel@tonic-gate 		freeValue(rval, 1);
772*0Sstevel@tonic-gate 		rval = 0;
773*0Sstevel@tonic-gate 		freeMappingItem(litem, numItems);
774*0Sstevel@tonic-gate 		litem = 0;
775*0Sstevel@tonic-gate 		numItems = 0;
776*0Sstevel@tonic-gate 	} /* for r < t->numRulesFromLDAP */
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 	statP = addSplitFieldValues(t, rvq, rv, count, domain);
779*0Sstevel@tonic-gate 
780*0Sstevel@tonic-gate 	if (rvq)
781*0Sstevel@tonic-gate 		freeRuleValue(rvq, count);
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 	if (verifyIndexMatch(t, 0, rv, 0, 0) == 0)
784*0Sstevel@tonic-gate 		return (MAP_INDEXLIST_ERROR);
785*0Sstevel@tonic-gate 	return (statP);
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate } /* end of buildNISRuleValue */
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate /*
790*0Sstevel@tonic-gate  * Convert rule-value to datum using namefield information
791*0Sstevel@tonic-gate  */
792*0Sstevel@tonic-gate datum *
793*0Sstevel@tonic-gate ruleValueToDatum(__nis_table_mapping_t *t, __nis_rule_value_t *rv, int *statP) {
794*0Sstevel@tonic-gate 	__nis_value_t	*val;
795*0Sstevel@tonic-gate 	datum		*value;
796*0Sstevel@tonic-gate 	char		*str, *cstr, commentSep[3] = {' ', 0, 0};
797*0Sstevel@tonic-gate 	char		*myself = "ruleValueToDatum";
798*0Sstevel@tonic-gate 
799*0Sstevel@tonic-gate 	/* No error yet */
800*0Sstevel@tonic-gate 	*statP = 0;
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate 	/* Return empty datum if no namefield information available */
803*0Sstevel@tonic-gate 	if (t->e == 0) {
804*0Sstevel@tonic-gate 		if ((value = am(myself, sizeof (*value))) == 0)
805*0Sstevel@tonic-gate 			*statP = MAP_NO_MEMORY;
806*0Sstevel@tonic-gate 		return (value);
807*0Sstevel@tonic-gate 	}
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 	val = getMappingFormatArray(t->e->element.match.fmt, rv,
810*0Sstevel@tonic-gate 				fa_item, t->e->element.match.numItems,
811*0Sstevel@tonic-gate 				t->e->element.match.item);
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate 	if (val && val->val && val->val->value) {
814*0Sstevel@tonic-gate 		if ((value = am(myself, sizeof (*value))) == 0) {
815*0Sstevel@tonic-gate 			*statP = MAP_NO_MEMORY;
816*0Sstevel@tonic-gate 			freeValue(val, 1);
817*0Sstevel@tonic-gate 			return (0);
818*0Sstevel@tonic-gate 		}
819*0Sstevel@tonic-gate 
820*0Sstevel@tonic-gate 		/* Strip trailing whitespaces */
821*0Sstevel@tonic-gate 		cstr = (char *)val->val->value + val->val->length;
822*0Sstevel@tonic-gate 		for (; cstr >= (char *)val->val->value &&
823*0Sstevel@tonic-gate 			(*cstr == ' ' || *cstr == '\t'); *cstr-- = '\0');
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 		if (t->commentChar != '\0' &&
826*0Sstevel@tonic-gate 		    (str = findVal(N2LCOMMENT, rv, mit_nisplus)) != 0 &&
827*0Sstevel@tonic-gate 		    *str != '\0') {
828*0Sstevel@tonic-gate 			commentSep[1] = t->commentChar;
829*0Sstevel@tonic-gate 			cstr = scat(myself, F, commentSep, str);
830*0Sstevel@tonic-gate 			if (cstr) {
831*0Sstevel@tonic-gate 				value->dptr = scat(myself, F,
832*0Sstevel@tonic-gate 						val->val->value, cstr);
833*0Sstevel@tonic-gate 				sfree(cstr);
834*0Sstevel@tonic-gate 			}
835*0Sstevel@tonic-gate 		} else {
836*0Sstevel@tonic-gate 			value->dptr = sdup(myself, T, val->val->value);
837*0Sstevel@tonic-gate 		}
838*0Sstevel@tonic-gate 		freeValue(val, 1);
839*0Sstevel@tonic-gate 		if (value->dptr) {
840*0Sstevel@tonic-gate 			value->dsize = strlen(value->dptr);
841*0Sstevel@tonic-gate 			return (value);
842*0Sstevel@tonic-gate 		} else {
843*0Sstevel@tonic-gate 			*statP = MAP_NO_MEMORY;
844*0Sstevel@tonic-gate 			sfree(value);
845*0Sstevel@tonic-gate 			return (0);
846*0Sstevel@tonic-gate 		}
847*0Sstevel@tonic-gate 	}
848*0Sstevel@tonic-gate 
849*0Sstevel@tonic-gate 	*statP = MAP_NAMEFIELD_MATCH_ERROR;
850*0Sstevel@tonic-gate 	return (0);
851*0Sstevel@tonic-gate }
852*0Sstevel@tonic-gate 
853*0Sstevel@tonic-gate datum *
854*0Sstevel@tonic-gate getKeyFromRuleValue(__nis_table_mapping_t *t, __nis_rule_value_t *rv, int *nv,
855*0Sstevel@tonic-gate 					int *statP) {
856*0Sstevel@tonic-gate 	int	i, j;
857*0Sstevel@tonic-gate 	datum	*key = 0;
858*0Sstevel@tonic-gate 	char	*str;
859*0Sstevel@tonic-gate 	char	*myself = "getKeyFromRuleValue";
860*0Sstevel@tonic-gate 
861*0Sstevel@tonic-gate 	/* No error yet */
862*0Sstevel@tonic-gate 	*statP = 0;
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate 	if (rv == 0 || nv == 0)
865*0Sstevel@tonic-gate 		return (0);
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate 	for (i = 0; i < rv->numColumns; i++) {
868*0Sstevel@tonic-gate 		if (rv->colName[i] == 0)
869*0Sstevel@tonic-gate 			continue;
870*0Sstevel@tonic-gate 		if (strcasecmp(N2LKEY, rv->colName[i]) == 0 ||
871*0Sstevel@tonic-gate 				strcasecmp(N2LIPKEY, rv->colName[i]) == 0) {
872*0Sstevel@tonic-gate 			if ((*nv = rv->colVal[i].numVals) == 0)
873*0Sstevel@tonic-gate 				return (0);
874*0Sstevel@tonic-gate 			if ((key = am(myself, sizeof (key[0]) * *nv)) == 0) {
875*0Sstevel@tonic-gate 				*statP = MAP_NO_MEMORY;
876*0Sstevel@tonic-gate 				return (0);
877*0Sstevel@tonic-gate 			}
878*0Sstevel@tonic-gate 			for (j = 0; j < *nv; j++) {
879*0Sstevel@tonic-gate 				if ((str = rv->colVal[i].val[j].value) == 0) {
880*0Sstevel@tonic-gate 					key[j].dsize = 0;
881*0Sstevel@tonic-gate 					key[j].dptr = 0;
882*0Sstevel@tonic-gate 				} else {
883*0Sstevel@tonic-gate 					if (verifyIndexMatch(t, 0, 0,
884*0Sstevel@tonic-gate 							rv->colName[i],
885*0Sstevel@tonic-gate 								str) == 0) {
886*0Sstevel@tonic-gate 						key[j].dsize = 0;
887*0Sstevel@tonic-gate 						key[j].dptr = 0;
888*0Sstevel@tonic-gate 						continue;
889*0Sstevel@tonic-gate 					}
890*0Sstevel@tonic-gate 					key[j].dsize = strlen(str);
891*0Sstevel@tonic-gate 					key[j].dptr = am(myself,
892*0Sstevel@tonic-gate 							key[j].dsize + 1);
893*0Sstevel@tonic-gate 					if (key[j].dptr == 0) {
894*0Sstevel@tonic-gate 						*statP = MAP_NO_MEMORY;
895*0Sstevel@tonic-gate 						for (--j; j >= 0; j--)
896*0Sstevel@tonic-gate 							sfree(key[j].dptr);
897*0Sstevel@tonic-gate 						sfree(key);
898*0Sstevel@tonic-gate 						return (0);
899*0Sstevel@tonic-gate 					}
900*0Sstevel@tonic-gate 					bcopy(str, key[j].dptr, key[j].dsize);
901*0Sstevel@tonic-gate 				}
902*0Sstevel@tonic-gate 			}
903*0Sstevel@tonic-gate 			return (key);
904*0Sstevel@tonic-gate 		}
905*0Sstevel@tonic-gate 	}
906*0Sstevel@tonic-gate 	return (0);
907*0Sstevel@tonic-gate }
908*0Sstevel@tonic-gate 
909*0Sstevel@tonic-gate /*
910*0Sstevel@tonic-gate  * Get the mapping structure corresponding to `map,domain.'
911*0Sstevel@tonic-gate  */
912*0Sstevel@tonic-gate __nis_table_mapping_t *
913*0Sstevel@tonic-gate mappingFromMap(char *map, char *domain, int *statP) {
914*0Sstevel@tonic-gate 	char			*mapPath;
915*0Sstevel@tonic-gate 	__nis_table_mapping_t	*t;
916*0Sstevel@tonic-gate 
917*0Sstevel@tonic-gate 	/* No error yet */
918*0Sstevel@tonic-gate 	*statP = 0;
919*0Sstevel@tonic-gate 
920*0Sstevel@tonic-gate 	/* Construct map,domain. */
921*0Sstevel@tonic-gate 	if ((mapPath = getFullMapName(map, domain)) == 0) {
922*0Sstevel@tonic-gate 		*statP = MAP_NO_MEMORY;
923*0Sstevel@tonic-gate 		return (0);
924*0Sstevel@tonic-gate 	}
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 	/* Get the hash table entry for the mapPath */
927*0Sstevel@tonic-gate 	if ((t = __nis_find_item_mt(mapPath, &ldapMappingList, 1, 0))
928*0Sstevel@tonic-gate 			== 0) {
929*0Sstevel@tonic-gate 		*statP = MAP_NO_MAPPING_EXISTS;
930*0Sstevel@tonic-gate 	}
931*0Sstevel@tonic-gate 	sfree(mapPath);
932*0Sstevel@tonic-gate 	return (t);
933*0Sstevel@tonic-gate }
934*0Sstevel@tonic-gate 
935*0Sstevel@tonic-gate /*
936*0Sstevel@tonic-gate  * Verify at least one key value obtained from DIT matches the search key
937*0Sstevel@tonic-gate  * RETURNS:	 1	MATCH
938*0Sstevel@tonic-gate  *		 0	NO MATCH
939*0Sstevel@tonic-gate  *		-1	NO KEY FOUND
940*0Sstevel@tonic-gate  */
941*0Sstevel@tonic-gate static int
942*0Sstevel@tonic-gate verifyKey(char *key, __nis_rule_value_t *rv) {
943*0Sstevel@tonic-gate 	int	i, j;
944*0Sstevel@tonic-gate 	char	*sipkey, *str;
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate 	for (i = 0; i < rv->numColumns; i++) {
947*0Sstevel@tonic-gate 		if (rv->colName[i] == 0)
948*0Sstevel@tonic-gate 			continue;
949*0Sstevel@tonic-gate 		if (strcasecmp(N2LKEY, rv->colName[i]) == 0) {
950*0Sstevel@tonic-gate 			if (rv->colVal[i].val == 0)
951*0Sstevel@tonic-gate 				return (0);
952*0Sstevel@tonic-gate 			for (j = 0; j < rv->colVal[i].numVals; j++) {
953*0Sstevel@tonic-gate 				str = (char *)rv->colVal[i].val[j].value;
954*0Sstevel@tonic-gate 				if (str && strcmp(str, key) == 0)
955*0Sstevel@tonic-gate 					return (1);
956*0Sstevel@tonic-gate 			}
957*0Sstevel@tonic-gate 			return (0);
958*0Sstevel@tonic-gate 		} else if (strcasecmp(N2LIPKEY, rv->colName[i]) == 0) {
959*0Sstevel@tonic-gate 			if (checkIPaddress(key, strlen(key), &sipkey) > 0) {
960*0Sstevel@tonic-gate 				if (rv->colVal[i].val == 0)
961*0Sstevel@tonic-gate 					return (0);
962*0Sstevel@tonic-gate 				for (j = 0; j < rv->colVal[i].numVals; j++) {
963*0Sstevel@tonic-gate 					str = rv->colVal[i].val[j].value;
964*0Sstevel@tonic-gate 					if (str && strcmp(str, sipkey) == 0) {
965*0Sstevel@tonic-gate 						sfree(sipkey);
966*0Sstevel@tonic-gate 						return (1);
967*0Sstevel@tonic-gate 					}
968*0Sstevel@tonic-gate 				}
969*0Sstevel@tonic-gate 				sfree(sipkey);
970*0Sstevel@tonic-gate 			}
971*0Sstevel@tonic-gate 			return (0);
972*0Sstevel@tonic-gate 		}
973*0Sstevel@tonic-gate 	}
974*0Sstevel@tonic-gate 	return (-1);
975*0Sstevel@tonic-gate }
976*0Sstevel@tonic-gate 
977*0Sstevel@tonic-gate /*
978*0Sstevel@tonic-gate  * Read (i.e get and map) a single NIS entry from the LDAP DIT
979*0Sstevel@tonic-gate  */
980*0Sstevel@tonic-gate bool_t
981*0Sstevel@tonic-gate singleReadFromDIT(char *map, char *domain, datum *key, datum *value,
982*0Sstevel@tonic-gate 							int *statP) {
983*0Sstevel@tonic-gate 	__nis_table_mapping_t	*t;
984*0Sstevel@tonic-gate 	__nis_rule_value_t	*rv_request = 0, *rv_result = 0;
985*0Sstevel@tonic-gate 	__nis_ldap_search_t	*ls;
986*0Sstevel@tonic-gate 	__nis_object_dn_t	*objectDN = NULL;
987*0Sstevel@tonic-gate 	int			i, rc, nr = 0, nv = 0;
988*0Sstevel@tonic-gate 	datum			*datval = 0;
989*0Sstevel@tonic-gate 	char			*skey, *str, *sipkey;
990*0Sstevel@tonic-gate 	char			*myself = "singleReadFromDIT";
991*0Sstevel@tonic-gate 
992*0Sstevel@tonic-gate 	*statP = SUCCESS;
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate 	if (!map || !domain || !key || !value) {
995*0Sstevel@tonic-gate 		*statP = MAP_PARAM_ERROR;
996*0Sstevel@tonic-gate 		return (FALSE);
997*0Sstevel@tonic-gate 	}
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate 
1000*0Sstevel@tonic-gate 	/* Get the mapping information for the map */
1001*0Sstevel@tonic-gate 	if ((t = mappingFromMap(map, domain, statP)) == 0) {
1002*0Sstevel@tonic-gate 		/*
1003*0Sstevel@tonic-gate 		 * No problem. We don't handle this map and domain. Maybe it's
1004*0Sstevel@tonic-gate 		 * handled by a service other than NIS.
1005*0Sstevel@tonic-gate 		 */
1006*0Sstevel@tonic-gate 		return (FALSE);
1007*0Sstevel@tonic-gate 	}
1008*0Sstevel@tonic-gate 
1009*0Sstevel@tonic-gate 	/* NULL-terminated version of datum key for logging */
1010*0Sstevel@tonic-gate 	if ((skey = am(myself, key->dsize + 1)) == 0) {
1011*0Sstevel@tonic-gate 		*statP = MAP_NO_MEMORY;
1012*0Sstevel@tonic-gate 		return (FALSE);
1013*0Sstevel@tonic-gate 	}
1014*0Sstevel@tonic-gate 	(void) memcpy(skey, key->dptr, key->dsize);
1015*0Sstevel@tonic-gate 
1016*0Sstevel@tonic-gate 	if ((str = getFullMapName(map, domain)) == 0) {
1017*0Sstevel@tonic-gate 		*statP = MAP_NO_MEMORY;
1018*0Sstevel@tonic-gate 		return (FALSE);
1019*0Sstevel@tonic-gate 	}
1020*0Sstevel@tonic-gate 
1021*0Sstevel@tonic-gate 	/* For each alternate mapping */
1022*0Sstevel@tonic-gate 	for (; t != 0; t = t->next) {
1023*0Sstevel@tonic-gate 		/* Verify objName */
1024*0Sstevel@tonic-gate 		if (strcmp(str, t->objName) != 0) {
1025*0Sstevel@tonic-gate 			continue;
1026*0Sstevel@tonic-gate 		}
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate 		/* Verify if key matches the index */
1029*0Sstevel@tonic-gate 		if (verifyIndexMatch(t, 0, 0, N2LKEY, skey) == 0 ||
1030*0Sstevel@tonic-gate 			verifyIndexMatch(t, 0, 0, N2LIPKEY, skey) == 0)
1031*0Sstevel@tonic-gate 			continue;
1032*0Sstevel@tonic-gate 
1033*0Sstevel@tonic-gate 		/* Check if rulesFromLDAP are provided */
1034*0Sstevel@tonic-gate 		if (t->numRulesFromLDAP == 0) {
1035*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
1036*0Sstevel@tonic-gate 				"%s: No rulesFromLDAP information available "
1037*0Sstevel@tonic-gate 				"for %s (%s)", myself, t->dbId, map);
1038*0Sstevel@tonic-gate 			continue;
1039*0Sstevel@tonic-gate 		}
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 		/* Convert key into rule-value */
1042*0Sstevel@tonic-gate 		if ((rv_request = datumToRuleValue(key, 0, t, 0, domain, TRUE,
1043*0Sstevel@tonic-gate 								statP)) == 0) {
1044*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
1045*0Sstevel@tonic-gate 				"%s: Conversion error %d (NIS to name=value "
1046*0Sstevel@tonic-gate 				"pairs) for NIS key (%s) for %s (%s)",
1047*0Sstevel@tonic-gate 				myself, *statP, skey, t->dbId, map);
1048*0Sstevel@tonic-gate 			continue;
1049*0Sstevel@tonic-gate 		}
1050*0Sstevel@tonic-gate 		/* Convert rule-value into ldap request */
1051*0Sstevel@tonic-gate 		for (objectDN = t->objectDN; objectDN &&
1052*0Sstevel@tonic-gate 				objectDN->read.base;
1053*0Sstevel@tonic-gate 				objectDN = objectDN->next) {
1054*0Sstevel@tonic-gate 			ls = createLdapRequest(t, rv_request, 0, 1, NULL,
1055*0Sstevel@tonic-gate 								objectDN);
1056*0Sstevel@tonic-gate 			if (ls == 0) {
1057*0Sstevel@tonic-gate 				*statP = MAP_CREATE_LDAP_REQUEST_ERROR;
1058*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
1059*0Sstevel@tonic-gate 					"%s: Failed to create ldapSearch "
1060*0Sstevel@tonic-gate 					"request for "
1061*0Sstevel@tonic-gate 					"NIS key (%s) for %s (%s) "
1062*0Sstevel@tonic-gate 					"for base %s",
1063*0Sstevel@tonic-gate 					myself, skey, t->dbId, map,
1064*0Sstevel@tonic-gate 					objectDN->read.base);
1065*0Sstevel@tonic-gate 				continue;
1066*0Sstevel@tonic-gate 			}
1067*0Sstevel@tonic-gate 			ls->timeout.tv_sec = SINGLE_ACCESS_TIMEOUT_SEC;
1068*0Sstevel@tonic-gate 			ls->timeout.tv_usec = SINGLE_ACCESS_TIMEOUT_USEC;
1069*0Sstevel@tonic-gate 			/* Query LDAP */
1070*0Sstevel@tonic-gate 			nr = (ls->isDN)?0:-1;
1071*0Sstevel@tonic-gate 			rv_result = ldapSearch(ls, &nr, 0, statP);
1072*0Sstevel@tonic-gate 			freeLdapSearch(ls);
1073*0Sstevel@tonic-gate 			if (rv_result == 0) {
1074*0Sstevel@tonic-gate 				if (*statP == LDAP_NO_SUCH_OBJECT) {
1075*0Sstevel@tonic-gate 					/* Entry does not exist in */
1076*0Sstevel@tonic-gate 					/* the ldap server */
1077*0Sstevel@tonic-gate 				}
1078*0Sstevel@tonic-gate 				continue;
1079*0Sstevel@tonic-gate 			}
1080*0Sstevel@tonic-gate 			freeRuleValue(rv_request, 1);
1081*0Sstevel@tonic-gate 			rv_request = 0;
1082*0Sstevel@tonic-gate 
1083*0Sstevel@tonic-gate 			/* if result > 1, first match will be returned */
1084*0Sstevel@tonic-gate 			if (nr > 1) {
1085*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_INFO,
1086*0Sstevel@tonic-gate 					"%s: %d ldapSearch results "
1087*0Sstevel@tonic-gate 					"for NIS key (%s) "
1088*0Sstevel@tonic-gate 					"for %s (%s) for base %s. "
1089*0Sstevel@tonic-gate 					"First match will be returned ",
1090*0Sstevel@tonic-gate 					myself, nr, skey, t->dbId, map,
1091*0Sstevel@tonic-gate 					objectDN->read.base);
1092*0Sstevel@tonic-gate 			}
1093*0Sstevel@tonic-gate 
1094*0Sstevel@tonic-gate 			for (i = 0; i < nr; i++) {
1095*0Sstevel@tonic-gate 				/* Convert LDAP data to NIS equivalents */
1096*0Sstevel@tonic-gate 				*statP = buildNISRuleValue(t, &rv_result[i],
1097*0Sstevel@tonic-gate 								domain);
1098*0Sstevel@tonic-gate 				if (*statP == MAP_INDEXLIST_ERROR)
1099*0Sstevel@tonic-gate 					continue;
1100*0Sstevel@tonic-gate 
1101*0Sstevel@tonic-gate 				if (*statP != SUCCESS) {
1102*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1103*0Sstevel@tonic-gate 					"%s: Conversion error %d (LDAP to "
1104*0Sstevel@tonic-gate 					"name=value pairs) for NIS key (%s) "
1105*0Sstevel@tonic-gate 					"for %s (%s) for base %s", myself,
1106*0Sstevel@tonic-gate 					*statP, skey,
1107*0Sstevel@tonic-gate 					t->dbId, map, objectDN->read.base);
1108*0Sstevel@tonic-gate 					continue;
1109*0Sstevel@tonic-gate 				}
1110*0Sstevel@tonic-gate 
1111*0Sstevel@tonic-gate 			/*
1112*0Sstevel@tonic-gate 			 * Check if 'key' from the ldap result matches the key
1113*0Sstevel@tonic-gate 			 * provided by our caller
1114*0Sstevel@tonic-gate 			 */
1115*0Sstevel@tonic-gate 				if ((rc = verifyKey(skey, &rv_result[i]))
1116*0Sstevel@tonic-gate 						== -1) {
1117*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_INFO,
1118*0Sstevel@tonic-gate 					"%s: Cannot verify key from ldap "
1119*0Sstevel@tonic-gate 					"result for NIS key (%s) for %s (%s) "
1120*0Sstevel@tonic-gate 					"for base %s",
1121*0Sstevel@tonic-gate 					myself, skey, t->dbId, map,
1122*0Sstevel@tonic-gate 					objectDN->read.base);
1123*0Sstevel@tonic-gate 					continue;
1124*0Sstevel@tonic-gate 				}
1125*0Sstevel@tonic-gate 
1126*0Sstevel@tonic-gate 				if (rc == 1) {
1127*0Sstevel@tonic-gate 					datval = ruleValueToDatum(t,
1128*0Sstevel@tonic-gate 							&rv_result[i], statP);
1129*0Sstevel@tonic-gate 					if (datval == 0) {
1130*0Sstevel@tonic-gate 						logmsg(MSG_NOTIMECHECK,
1131*0Sstevel@tonic-gate 						LOG_WARNING,
1132*0Sstevel@tonic-gate 						"%s: Conversion error %d "
1133*0Sstevel@tonic-gate 						"(name=value pairs to NIS) "
1134*0Sstevel@tonic-gate 						"for NIS key (%s) for %s (%s)"
1135*0Sstevel@tonic-gate 						" for base %s",
1136*0Sstevel@tonic-gate 						myself,
1137*0Sstevel@tonic-gate 						*statP, skey, t->dbId, map,
1138*0Sstevel@tonic-gate 						objectDN->read.base);
1139*0Sstevel@tonic-gate 						continue;
1140*0Sstevel@tonic-gate 					}
1141*0Sstevel@tonic-gate 					if (value) {
1142*0Sstevel@tonic-gate 						value->dptr = datval->dptr;
1143*0Sstevel@tonic-gate 						value->dsize = datval->dsize;
1144*0Sstevel@tonic-gate 					}
1145*0Sstevel@tonic-gate 					sfree(datval);
1146*0Sstevel@tonic-gate 					sfree(skey);
1147*0Sstevel@tonic-gate 					freeRuleValue(rv_result, nr);
1148*0Sstevel@tonic-gate 					rv_result = 0;
1149*0Sstevel@tonic-gate 					*statP = SUCCESS;
1150*0Sstevel@tonic-gate 
1151*0Sstevel@tonic-gate 					/* Free full map name */
1152*0Sstevel@tonic-gate 					sfree(str);
1153*0Sstevel@tonic-gate 
1154*0Sstevel@tonic-gate 					return (TRUE);
1155*0Sstevel@tonic-gate 				}
1156*0Sstevel@tonic-gate 			}
1157*0Sstevel@tonic-gate 			freeRuleValue(rv_result, nr);
1158*0Sstevel@tonic-gate 			rv_result = 0;
1159*0Sstevel@tonic-gate 		}   /* end of for over objectDN */
1160*0Sstevel@tonic-gate 
1161*0Sstevel@tonic-gate 		if (rv_request != 0) {
1162*0Sstevel@tonic-gate 			freeRuleValue(rv_request, 1);
1163*0Sstevel@tonic-gate 			rv_request = 0;
1164*0Sstevel@tonic-gate 		}
1165*0Sstevel@tonic-gate 		if (rv_result != 0) {
1166*0Sstevel@tonic-gate 			freeRuleValue(rv_result, nr);
1167*0Sstevel@tonic-gate 			rv_result = 0;
1168*0Sstevel@tonic-gate 		}
1169*0Sstevel@tonic-gate 	}
1170*0Sstevel@tonic-gate 	sfree(skey);
1171*0Sstevel@tonic-gate 	*statP = MAP_NO_MATCHING_KEY;
1172*0Sstevel@tonic-gate 
1173*0Sstevel@tonic-gate 	/* Free full map name */
1174*0Sstevel@tonic-gate 	sfree(str);
1175*0Sstevel@tonic-gate 
1176*0Sstevel@tonic-gate 	return (FALSE);
1177*0Sstevel@tonic-gate }
1178*0Sstevel@tonic-gate 
1179*0Sstevel@tonic-gate 
1180*0Sstevel@tonic-gate /*
1181*0Sstevel@tonic-gate  * Maps and writes a single NIS entry to the LDAP DIT
1182*0Sstevel@tonic-gate  */
1183*0Sstevel@tonic-gate int
1184*0Sstevel@tonic-gate singleWriteToDIT(char *map, char *domain, datum *key, datum *value,
1185*0Sstevel@tonic-gate 						bool_t replace) {
1186*0Sstevel@tonic-gate 	__nis_table_mapping_t	*t;
1187*0Sstevel@tonic-gate 	__nis_rule_value_t	*rv, *frv;
1188*0Sstevel@tonic-gate 	__nis_ldap_search_t	*ls;
1189*0Sstevel@tonic-gate 	int			statP = SUCCESS, flag;
1190*0Sstevel@tonic-gate 	int			nv, nr, i, rc, collapse;
1191*0Sstevel@tonic-gate 	char			*dn = 0, *skey, *svalue, *str;
1192*0Sstevel@tonic-gate 	char			*myself = "singleWriteToDIT";
1193*0Sstevel@tonic-gate 
1194*0Sstevel@tonic-gate 	if (!map || !domain || !key || !value) {
1195*0Sstevel@tonic-gate 		return (MAP_PARAM_ERROR);
1196*0Sstevel@tonic-gate 	}
1197*0Sstevel@tonic-gate 
1198*0Sstevel@tonic-gate 	/* Return SUCCESS for empty or whitespace key */
1199*0Sstevel@tonic-gate 	for (i = 0; i < key->dsize && (key->dptr[i] == 0 ||
1200*0Sstevel@tonic-gate 		key->dptr[i] == ' ' || key->dptr[i] == '\t'); i++);
1201*0Sstevel@tonic-gate 	if (i >= key->dsize)
1202*0Sstevel@tonic-gate 		return (SUCCESS);
1203*0Sstevel@tonic-gate 
1204*0Sstevel@tonic-gate 	/* Get the mapping information for the map */
1205*0Sstevel@tonic-gate 	if ((t = mappingFromMap(map, domain, &statP)) == 0) {
1206*0Sstevel@tonic-gate 		/*
1207*0Sstevel@tonic-gate 		 * No problem. We don't handle this map and domain. Maybe it's
1208*0Sstevel@tonic-gate 		 * handled by a service other than NIS.
1209*0Sstevel@tonic-gate 		 */
1210*0Sstevel@tonic-gate 		return (statP);
1211*0Sstevel@tonic-gate 	}
1212*0Sstevel@tonic-gate 
1213*0Sstevel@tonic-gate 	/* NULL-terminated version of key and value for logging */
1214*0Sstevel@tonic-gate 	if ((skey = am(myself, key->dsize + 1)) == 0)
1215*0Sstevel@tonic-gate 		return (MAP_NO_MEMORY);
1216*0Sstevel@tonic-gate 	(void) memcpy(skey, key->dptr, key->dsize);
1217*0Sstevel@tonic-gate 
1218*0Sstevel@tonic-gate 	if ((svalue = am(myself, value->dsize + 1)) == 0) {
1219*0Sstevel@tonic-gate 		sfree(skey);
1220*0Sstevel@tonic-gate 		return (MAP_NO_MEMORY);
1221*0Sstevel@tonic-gate 	}
1222*0Sstevel@tonic-gate 	(void) memcpy(svalue, value->dptr, value->dsize);
1223*0Sstevel@tonic-gate 
1224*0Sstevel@tonic-gate 	if ((str = getFullMapName(map, domain)) == 0) {
1225*0Sstevel@tonic-gate 		sfree(skey);
1226*0Sstevel@tonic-gate 		sfree(svalue);
1227*0Sstevel@tonic-gate 		return (MAP_NO_MEMORY);
1228*0Sstevel@tonic-gate 	}
1229*0Sstevel@tonic-gate 
1230*0Sstevel@tonic-gate 	/* For each alternate mapping */
1231*0Sstevel@tonic-gate 	for (flag = 0; t != 0; t = t->next) {
1232*0Sstevel@tonic-gate 		/* Verify objName */
1233*0Sstevel@tonic-gate 		if (strcmp(str, t->objName) != 0) {
1234*0Sstevel@tonic-gate 			continue;
1235*0Sstevel@tonic-gate 		}
1236*0Sstevel@tonic-gate 
1237*0Sstevel@tonic-gate 		/* Verify if key matches the index */
1238*0Sstevel@tonic-gate 		if (verifyIndexMatch(t, 0, 0, N2LKEY, skey) == 0 ||
1239*0Sstevel@tonic-gate 			verifyIndexMatch(t, 0, 0, N2LIPKEY, skey) == 0)
1240*0Sstevel@tonic-gate 			continue;
1241*0Sstevel@tonic-gate 
1242*0Sstevel@tonic-gate 		/* Check the writespecs */
1243*0Sstevel@tonic-gate 		if (t->objectDN->write.base == 0) {
1244*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
1245*0Sstevel@tonic-gate 				"%s: No baseDN in writespec. Write disabled "
1246*0Sstevel@tonic-gate 				"for %s (%s)", myself, t->dbId, map);
1247*0Sstevel@tonic-gate 			continue;
1248*0Sstevel@tonic-gate 		}
1249*0Sstevel@tonic-gate 
1250*0Sstevel@tonic-gate 		/* Check if rulesToLDAP are provided */
1251*0Sstevel@tonic-gate 		if (t->numRulesToLDAP == 0) {
1252*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
1253*0Sstevel@tonic-gate 				"%s: No rulesToLDAP. Write disabled for "
1254*0Sstevel@tonic-gate 				"%s (%s)", myself, t->dbId, map);
1255*0Sstevel@tonic-gate 			continue;
1256*0Sstevel@tonic-gate 		}
1257*0Sstevel@tonic-gate 
1258*0Sstevel@tonic-gate 		/* Set flag to indicate write is enabled */
1259*0Sstevel@tonic-gate 		flag = 1;
1260*0Sstevel@tonic-gate 
1261*0Sstevel@tonic-gate 		/* Convert key  and value into an array of rule-values */
1262*0Sstevel@tonic-gate 		if ((rv = datumToRuleValue(key, value, t, &nv, domain, FALSE,
1263*0Sstevel@tonic-gate 								&statP)) == 0) {
1264*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
1265*0Sstevel@tonic-gate 				"%s: Conversion error %d (NIS to name=value "
1266*0Sstevel@tonic-gate 				"pairs) for NIS data (key=%s, value=%s) "
1267*0Sstevel@tonic-gate 				"for %s (%s)",
1268*0Sstevel@tonic-gate 				myself, statP, skey, svalue, t->dbId, map);
1269*0Sstevel@tonic-gate 			sfree(skey);
1270*0Sstevel@tonic-gate 			sfree(svalue);
1271*0Sstevel@tonic-gate 
1272*0Sstevel@tonic-gate 			/* Free full map name */
1273*0Sstevel@tonic-gate 			sfree(str);
1274*0Sstevel@tonic-gate 
1275*0Sstevel@tonic-gate 			return (statP);
1276*0Sstevel@tonic-gate 		}
1277*0Sstevel@tonic-gate 
1278*0Sstevel@tonic-gate 		/* Convert NIS data to LDAP equivalents for each rule-value */
1279*0Sstevel@tonic-gate 		for (i = 0; i < nv; i++) {
1280*0Sstevel@tonic-gate 			/* Verify indexlist with name=value pairs */
1281*0Sstevel@tonic-gate 			if (verifyIndexMatch(t, 0, &rv[i], 0, 0) == 0)
1282*0Sstevel@tonic-gate 				break;
1283*0Sstevel@tonic-gate 
1284*0Sstevel@tonic-gate 			/* Create LDAP request and LDAP name=value pairs */
1285*0Sstevel@tonic-gate 			if ((ls = createLdapRequest(t, &rv[i],
1286*0Sstevel@tonic-gate 			    0, 0, NULL, NULL)) == 0) {
1287*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
1288*0Sstevel@tonic-gate 					"%s: Conversion error (name=value pairs"
1289*0Sstevel@tonic-gate 					" to LDAP) for NIS data "
1290*0Sstevel@tonic-gate 					"(key=%s, value=%s) for %s (%s)",
1291*0Sstevel@tonic-gate 					myself, skey, svalue, t->dbId, map);
1292*0Sstevel@tonic-gate 				freeRuleValue(rv, nv);
1293*0Sstevel@tonic-gate 				sfree(skey);
1294*0Sstevel@tonic-gate 				sfree(svalue);
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate 				/* Free full map name */
1297*0Sstevel@tonic-gate 				sfree(str);
1298*0Sstevel@tonic-gate 
1299*0Sstevel@tonic-gate 				return (MAP_CREATE_LDAP_REQUEST_ERROR);
1300*0Sstevel@tonic-gate 			}
1301*0Sstevel@tonic-gate 			freeLdapSearch(ls);
1302*0Sstevel@tonic-gate 			/* printRuleValue(&rv[i]); */
1303*0Sstevel@tonic-gate 		}
1304*0Sstevel@tonic-gate 
1305*0Sstevel@tonic-gate 		/* If i < nv then this alternate mapping isn't the one */
1306*0Sstevel@tonic-gate 		if (i < nv)
1307*0Sstevel@tonic-gate 			continue;
1308*0Sstevel@tonic-gate 
1309*0Sstevel@tonic-gate 		/*
1310*0Sstevel@tonic-gate 		 * Merge rule-values with the same DN so that we have
1311*0Sstevel@tonic-gate 		 * one ldap write request for each DN
1312*0Sstevel@tonic-gate 		 */
1313*0Sstevel@tonic-gate 		nr = nv;
1314*0Sstevel@tonic-gate 		frv = mergeRuleValueWithSameDN(rv, &nr);
1315*0Sstevel@tonic-gate 		freeRuleValue(rv, nv);
1316*0Sstevel@tonic-gate 		if (frv == 0) {
1317*0Sstevel@tonic-gate 			if (nr == -1) {
1318*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
1319*0Sstevel@tonic-gate 					"%s: Unable to merge LDAP write "
1320*0Sstevel@tonic-gate 					"requests to same DN for NIS data "
1321*0Sstevel@tonic-gate 					"(key=%s, value=%s) for %s (%s)",
1322*0Sstevel@tonic-gate 					myself, skey, svalue, t->dbId, map);
1323*0Sstevel@tonic-gate 				statP = MAP_INTERNAL_ERROR;
1324*0Sstevel@tonic-gate 			} else if (nr == 0) {
1325*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1326*0Sstevel@tonic-gate 					"%s: Cannot generate write DN due to "
1327*0Sstevel@tonic-gate 					"missing information for NIS data "
1328*0Sstevel@tonic-gate 					"(key=%s, value=%s) for %s (%s)",
1329*0Sstevel@tonic-gate 					myself, skey, svalue, t->dbId, map);
1330*0Sstevel@tonic-gate 				statP = MAP_NO_DN;
1331*0Sstevel@tonic-gate 			}
1332*0Sstevel@tonic-gate 			sfree(skey);
1333*0Sstevel@tonic-gate 			sfree(svalue);
1334*0Sstevel@tonic-gate 
1335*0Sstevel@tonic-gate 			/* Free full map name */
1336*0Sstevel@tonic-gate 			sfree(str);
1337*0Sstevel@tonic-gate 
1338*0Sstevel@tonic-gate 			return (statP);
1339*0Sstevel@tonic-gate 		}
1340*0Sstevel@tonic-gate 
1341*0Sstevel@tonic-gate 		/* Write to the LDAP server */
1342*0Sstevel@tonic-gate 		for (collapse = 0, i = 0; i < nr; i++) {
1343*0Sstevel@tonic-gate 			if ((dn = findVal("dn", &frv[i], mit_ldap)) != 0) {
1344*0Sstevel@tonic-gate 				if (replace == FALSE) {
1345*0Sstevel@tonic-gate 					/* ldap add */
1346*0Sstevel@tonic-gate 					rc = ldapAdd(dn, &frv[i],
1347*0Sstevel@tonic-gate 						t->objectDN->write.attrs, 0);
1348*0Sstevel@tonic-gate 				} else {
1349*0Sstevel@tonic-gate 					/* ldap modify with addFirst set */
1350*0Sstevel@tonic-gate 					rc = ldapModify(dn, &frv[i],
1351*0Sstevel@tonic-gate 						t->objectDN->write.attrs, 1);
1352*0Sstevel@tonic-gate 				}
1353*0Sstevel@tonic-gate 
1354*0Sstevel@tonic-gate 				/* if we get err=20, collapse and try again */
1355*0Sstevel@tonic-gate 				if (!collapse &&
1356*0Sstevel@tonic-gate 					(rc == LDAP_TYPE_OR_VALUE_EXISTS) &&
1357*0Sstevel@tonic-gate 					(collapseRuleValue(&frv[i]) == 1)) {
1358*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1359*0Sstevel@tonic-gate 						"%s: Ignoring values differing "
1360*0Sstevel@tonic-gate 						"in case from NIS data (key=%s,"
1361*0Sstevel@tonic-gate 						" value=%s) for (dn: %s) for "
1362*0Sstevel@tonic-gate 						"%s (%s)", myself, skey,
1363*0Sstevel@tonic-gate 						svalue, dn, t->dbId, map);
1364*0Sstevel@tonic-gate 					collapse = 1;
1365*0Sstevel@tonic-gate 					i--;
1366*0Sstevel@tonic-gate 					continue;
1367*0Sstevel@tonic-gate 				}
1368*0Sstevel@tonic-gate 
1369*0Sstevel@tonic-gate 				collapse = 0;
1370*0Sstevel@tonic-gate 				if (rc != LDAP_SUCCESS) {
1371*0Sstevel@tonic-gate 					/* Log error */
1372*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
1373*0Sstevel@tonic-gate 						"%s: %s error %d (%s) for "
1374*0Sstevel@tonic-gate 						"(dn: %s) for NIS data "
1375*0Sstevel@tonic-gate 						"(key=%s, value=%s) "
1376*0Sstevel@tonic-gate 						"for %s (%s)",
1377*0Sstevel@tonic-gate 						myself, (replace == TRUE) ?
1378*0Sstevel@tonic-gate 						"ldapModify" : "ldapAdd", rc,
1379*0Sstevel@tonic-gate 						ldap_err2string(rc), dn, skey,
1380*0Sstevel@tonic-gate 						svalue, t->dbId, map);
1381*0Sstevel@tonic-gate 
1382*0Sstevel@tonic-gate 					/* Dumping failed call may be useful */
1383*0Sstevel@tonic-gate 					/* printRuleValue(&frv[i]); */
1384*0Sstevel@tonic-gate 
1385*0Sstevel@tonic-gate 					/*
1386*0Sstevel@tonic-gate 					 * Return the error code and let wrapper
1387*0Sstevel@tonic-gate 					 * sort out if mapping should continue
1388*0Sstevel@tonic-gate 					 * or abort.
1389*0Sstevel@tonic-gate 					 */
1390*0Sstevel@tonic-gate 					statP = rc;
1391*0Sstevel@tonic-gate 					sfree(skey);
1392*0Sstevel@tonic-gate 					sfree(svalue);
1393*0Sstevel@tonic-gate 					freeRuleValue(frv, nr);
1394*0Sstevel@tonic-gate 
1395*0Sstevel@tonic-gate 					/* Free full map name */
1396*0Sstevel@tonic-gate 					sfree(str);
1397*0Sstevel@tonic-gate 
1398*0Sstevel@tonic-gate 					return (statP);
1399*0Sstevel@tonic-gate 				}
1400*0Sstevel@tonic-gate 			}
1401*0Sstevel@tonic-gate 		}
1402*0Sstevel@tonic-gate 
1403*0Sstevel@tonic-gate 		freeRuleValue(frv, nr);
1404*0Sstevel@tonic-gate 	}
1405*0Sstevel@tonic-gate 
1406*0Sstevel@tonic-gate 	sfree(skey);
1407*0Sstevel@tonic-gate 	sfree(svalue);
1408*0Sstevel@tonic-gate 
1409*0Sstevel@tonic-gate 	/* Free full map name */
1410*0Sstevel@tonic-gate 	sfree(str);
1411*0Sstevel@tonic-gate 
1412*0Sstevel@tonic-gate 	return ((flag)?SUCCESS:MAP_WRITE_DISABLED);
1413*0Sstevel@tonic-gate }
1414*0Sstevel@tonic-gate 
1415*0Sstevel@tonic-gate suc_code
1416*0Sstevel@tonic-gate collapseRuleValue(__nis_rule_value_t *rv) {
1417*0Sstevel@tonic-gate 	int		i, j, k, flag;
1418*0Sstevel@tonic-gate 
1419*0Sstevel@tonic-gate 	/* Using 'val' to appease cstyle's 80 chars/line limit */
1420*0Sstevel@tonic-gate 	__nis_value_t	*val;
1421*0Sstevel@tonic-gate 
1422*0Sstevel@tonic-gate 	for (i = 0, flag = 0; i < rv->numAttrs; i++) {
1423*0Sstevel@tonic-gate 		val = &rv->attrVal[i];
1424*0Sstevel@tonic-gate 		for (j = 1; j < val->numVals; j++) {
1425*0Sstevel@tonic-gate 			for (k = 0; k < j; k++) {
1426*0Sstevel@tonic-gate 				if (val->val[j].length != val->val[k].length)
1427*0Sstevel@tonic-gate 					continue;
1428*0Sstevel@tonic-gate 				if (val->val[k].length == 0)
1429*0Sstevel@tonic-gate 					continue;
1430*0Sstevel@tonic-gate 				if (strncasecmp(val->val[j].value,
1431*0Sstevel@tonic-gate 						val->val[k].value,
1432*0Sstevel@tonic-gate 						val->val[j].length) != 0)
1433*0Sstevel@tonic-gate 					continue;
1434*0Sstevel@tonic-gate 				flag = 1;
1435*0Sstevel@tonic-gate 				sfree(val->val[j].value);
1436*0Sstevel@tonic-gate 
1437*0Sstevel@tonic-gate #ifdef	ORDER_NOT_IMPORTANT
1438*0Sstevel@tonic-gate 				val->val[j--] = val->val[--val->numVals];
1439*0Sstevel@tonic-gate #else
1440*0Sstevel@tonic-gate 				/* Order needs to be maintained */
1441*0Sstevel@tonic-gate 				for (k = j + 1; k < val->numVals; k++)
1442*0Sstevel@tonic-gate 					val->val[k - 1] = val->val[k];
1443*0Sstevel@tonic-gate 				j--;
1444*0Sstevel@tonic-gate 				val->numVals--;
1445*0Sstevel@tonic-gate #endif
1446*0Sstevel@tonic-gate 				break;
1447*0Sstevel@tonic-gate 			}
1448*0Sstevel@tonic-gate 		}
1449*0Sstevel@tonic-gate 	}
1450*0Sstevel@tonic-gate 	return (flag);
1451*0Sstevel@tonic-gate }
1452*0Sstevel@tonic-gate 
1453*0Sstevel@tonic-gate /* ObjectClass lookup table */
1454*0Sstevel@tonic-gate static struct {
1455*0Sstevel@tonic-gate 	const char *attrType;
1456*0Sstevel@tonic-gate 	const char *objectClass;
1457*0Sstevel@tonic-gate } oc_lookup[] = {
1458*0Sstevel@tonic-gate 	{ "o",				"objectclass=organization"},
1459*0Sstevel@tonic-gate 	{ "organizationname",		"objectclass=organization"},
1460*0Sstevel@tonic-gate 	{ "2.5.4.10",			"objectclass=organization"},
1461*0Sstevel@tonic-gate 	{ "ou",				"objectclass=organizationalunit"},
1462*0Sstevel@tonic-gate 	{ "organizationalunitname",	"objectclass=organizationalunit"},
1463*0Sstevel@tonic-gate 	{ "2.5.4.11",			"objectclass=organizationalunit"},
1464*0Sstevel@tonic-gate 	{ "c",				"objectclass=country"},
1465*0Sstevel@tonic-gate 	{ "countryname",		"objectclass=country"},
1466*0Sstevel@tonic-gate 	{ "2.5.4.6",			"objectclass=country"},
1467*0Sstevel@tonic-gate 	{ "dc",				"objectclass=domain"},
1468*0Sstevel@tonic-gate 	{ "domaincomponent",		"objectclass=domain"},
1469*0Sstevel@tonic-gate 	{ "0.9.2342.19200300.100.1.25",	"objectclass=domain"},
1470*0Sstevel@tonic-gate 	{ "nismapname",			"objectclass=nismap"},
1471*0Sstevel@tonic-gate 	{ "1.3.6.1.1.1.1.26",		"objectclass=nismap"},
1472*0Sstevel@tonic-gate 	{ "automountmapname",		"objectclass=automountmap"},
1473*0Sstevel@tonic-gate 	{ "1.3.6.1.1.1.1.31",		"objectclass=automountmap"},
1474*0Sstevel@tonic-gate 	{ 0,				0}
1475*0Sstevel@tonic-gate };
1476*0Sstevel@tonic-gate 
1477*0Sstevel@tonic-gate /*
1478*0Sstevel@tonic-gate  * Returns the name of the objectclass to which the object
1479*0Sstevel@tonic-gate  * represented by the given 'rdn' will most likely belong to.
1480*0Sstevel@tonic-gate  * The return value is in static memory so it should not be
1481*0Sstevel@tonic-gate  * freed
1482*0Sstevel@tonic-gate  */
1483*0Sstevel@tonic-gate const char *
1484*0Sstevel@tonic-gate getObjectClass(char *rdn) {
1485*0Sstevel@tonic-gate 
1486*0Sstevel@tonic-gate 	char *attrtype, *p;
1487*0Sstevel@tonic-gate 	int len, i;
1488*0Sstevel@tonic-gate 
1489*0Sstevel@tonic-gate 	/* Skip leading whitespaces */
1490*0Sstevel@tonic-gate 	for (p = rdn; *p == ' ' || *p == '\t'; p++);
1491*0Sstevel@tonic-gate 	if (*p == '\0')
1492*0Sstevel@tonic-gate 		return (0);
1493*0Sstevel@tonic-gate 	attrtype = p;
1494*0Sstevel@tonic-gate 
1495*0Sstevel@tonic-gate 	/* Find '=' */
1496*0Sstevel@tonic-gate 	if ((p = strchr(attrtype, '=')) == 0 || p == attrtype ||
1497*0Sstevel@tonic-gate 						*(p - 1) == '\\')
1498*0Sstevel@tonic-gate 		return (0);
1499*0Sstevel@tonic-gate 
1500*0Sstevel@tonic-gate 	/*
1501*0Sstevel@tonic-gate 	 * Skip trailing whitespaces in attrtype
1502*0Sstevel@tonic-gate 	 * Don't worry, p won't decrease beyond attrtype
1503*0Sstevel@tonic-gate 	 */
1504*0Sstevel@tonic-gate 	for (--p; *p == ' ' || *p == '\t'; p--);
1505*0Sstevel@tonic-gate 	len = p - attrtype + 1;
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate 	for (i = 0; oc_lookup[i].attrType; i++)
1508*0Sstevel@tonic-gate 		if (!strncasecmp(oc_lookup[i].attrType, attrtype, len))
1509*0Sstevel@tonic-gate 			/* Check length is right */
1510*0Sstevel@tonic-gate 			if (len == strlen(oc_lookup[i].attrType))
1511*0Sstevel@tonic-gate 				return (oc_lookup[i].objectClass);
1512*0Sstevel@tonic-gate 
1513*0Sstevel@tonic-gate 	return (0);
1514*0Sstevel@tonic-gate }
1515*0Sstevel@tonic-gate 
1516*0Sstevel@tonic-gate /*
1517*0Sstevel@tonic-gate  * Split 'dn' into rdn and parentdn based on the first
1518*0Sstevel@tonic-gate  * occurrence of unescaped 'comma' or 'semicolon'. rdn
1519*0Sstevel@tonic-gate  * lies on the LHS while parentdn lies on the RHS of the
1520*0Sstevel@tonic-gate  * split. If none found, then an empty string ("") is
1521*0Sstevel@tonic-gate  * assigned to parentdn
1522*0Sstevel@tonic-gate  */
1523*0Sstevel@tonic-gate int
1524*0Sstevel@tonic-gate splitDN(char *dn, char **rdn, char **parentdn) {
1525*0Sstevel@tonic-gate 	char	*value, *name;
1526*0Sstevel@tonic-gate 	char	*myself = "splitDN";
1527*0Sstevel@tonic-gate 
1528*0Sstevel@tonic-gate 	if ((name = sdup(myself, T, dn)) == 0)
1529*0Sstevel@tonic-gate 		return (-1);
1530*0Sstevel@tonic-gate 
1531*0Sstevel@tonic-gate 	for (value = name; *value != '\0'; value++) {
1532*0Sstevel@tonic-gate 		if (*value == ',' || *value == ';')
1533*0Sstevel@tonic-gate 			if (value == name || *(value - 1) != '\\')
1534*0Sstevel@tonic-gate 				break;
1535*0Sstevel@tonic-gate 	}
1536*0Sstevel@tonic-gate 
1537*0Sstevel@tonic-gate 	if (*value != '\0') {
1538*0Sstevel@tonic-gate 		*value = '\0';
1539*0Sstevel@tonic-gate 		value++;
1540*0Sstevel@tonic-gate 	} else
1541*0Sstevel@tonic-gate 		value = 0;
1542*0Sstevel@tonic-gate 
1543*0Sstevel@tonic-gate 	if (parentdn) {
1544*0Sstevel@tonic-gate 		if ((*parentdn = sdup(myself, T, value)) == 0) {
1545*0Sstevel@tonic-gate 			sfree(name);
1546*0Sstevel@tonic-gate 			return (-1);
1547*0Sstevel@tonic-gate 		}
1548*0Sstevel@tonic-gate 	}
1549*0Sstevel@tonic-gate 	if (rdn)
1550*0Sstevel@tonic-gate 		*rdn = name;
1551*0Sstevel@tonic-gate 	else
1552*0Sstevel@tonic-gate 		sfree(name);
1553*0Sstevel@tonic-gate 
1554*0Sstevel@tonic-gate 	return (1);
1555*0Sstevel@tonic-gate }
1556*0Sstevel@tonic-gate 
1557*0Sstevel@tonic-gate /*
1558*0Sstevel@tonic-gate  * FUNCTION :	makeNISObject()
1559*0Sstevel@tonic-gate  *
1560*0Sstevel@tonic-gate  * DESCRIPTION: Sets up a nis Object in the DIT.
1561*0Sstevel@tonic-gate  *
1562*0Sstevel@tonic-gate  * GIVEN :
1563*0Sstevel@tonic-gate  *		Case 1: Both 'domain' and 'dn' are non-NULL
1564*0Sstevel@tonic-gate  *			Create nisDomainObject with the given information
1565*0Sstevel@tonic-gate  *		Case 2: Only 'domain' is  non-NULL
1566*0Sstevel@tonic-gate  *			Obtain the 'dn' from the nisLDAPdomainContext list
1567*0Sstevel@tonic-gate  *			Create nisDomainObject with the above information
1568*0Sstevel@tonic-gate  *		Case 3: Only 'dn' is  non-NULL
1569*0Sstevel@tonic-gate  *			Create an object with the 'dn'
1570*0Sstevel@tonic-gate  *			Here we guess the objectclass attribute, based on
1571*0Sstevel@tonic-gate  *			oc_lookup table
1572*0Sstevel@tonic-gate  *		Case 4: Both 'domain' and 'dn' are NULL
1573*0Sstevel@tonic-gate  *			Error
1574*0Sstevel@tonic-gate  *
1575*0Sstevel@tonic-gate  * RETURNS :	SUCCESS = It worked
1576*0Sstevel@tonic-gate  *		FAILURE = There was a problem.
1577*0Sstevel@tonic-gate  */
1578*0Sstevel@tonic-gate suc_code
1579*0Sstevel@tonic-gate makeNISObject(char *domain, char *dn) {
1580*0Sstevel@tonic-gate 	__nis_rule_value_t	*rv;
1581*0Sstevel@tonic-gate 	__nis_ldap_search_t	*ls;
1582*0Sstevel@tonic-gate 	int			i, rc, nr, add_rc;
1583*0Sstevel@tonic-gate 	char			*val;
1584*0Sstevel@tonic-gate 	char			*myself = "makeNISObject";
1585*0Sstevel@tonic-gate 
1586*0Sstevel@tonic-gate 	if (!dn && !domain)
1587*0Sstevel@tonic-gate 		return (FAILURE);
1588*0Sstevel@tonic-gate 
1589*0Sstevel@tonic-gate 	/*
1590*0Sstevel@tonic-gate 	 * If only 'domain' name is provided, then
1591*0Sstevel@tonic-gate 	 * try to find dn from the nisLDAPdomainContext
1592*0Sstevel@tonic-gate 	 * list generated by the parser
1593*0Sstevel@tonic-gate 	 */
1594*0Sstevel@tonic-gate 	if (!dn) {
1595*0Sstevel@tonic-gate 		for (i = 0; i < ypDomains.numDomains; i++) {
1596*0Sstevel@tonic-gate 			if (ypDomains.domainLabels[i] == 0)
1597*0Sstevel@tonic-gate 				continue;
1598*0Sstevel@tonic-gate 			if (strcasecmp(domain, ypDomains.domainLabels[i])
1599*0Sstevel@tonic-gate 								== 0) {
1600*0Sstevel@tonic-gate 				dn = ypDomains.domains[i];
1601*0Sstevel@tonic-gate 				break;
1602*0Sstevel@tonic-gate 			}
1603*0Sstevel@tonic-gate 		}
1604*0Sstevel@tonic-gate 		if (!dn)
1605*0Sstevel@tonic-gate 			return (FAILURE);
1606*0Sstevel@tonic-gate 	}
1607*0Sstevel@tonic-gate 
1608*0Sstevel@tonic-gate 	/*
1609*0Sstevel@tonic-gate 	 * If only 'dn' is given, then it means that the
1610*0Sstevel@tonic-gate 	 * caller simply wants to a create an entry for
1611*0Sstevel@tonic-gate 	 * that 'dn'.
1612*0Sstevel@tonic-gate 	 *
1613*0Sstevel@tonic-gate 	 * If 'domain' is given, then check if the 'dn'
1614*0Sstevel@tonic-gate 	 * has already been set up as a nis domain object.
1615*0Sstevel@tonic-gate 	 * If not, see if we can make it become one.
1616*0Sstevel@tonic-gate 	 */
1617*0Sstevel@tonic-gate 	if (domain) {
1618*0Sstevel@tonic-gate 		/*
1619*0Sstevel@tonic-gate 		 * Check to see if the nis domain object has
1620*0Sstevel@tonic-gate 		 * already been set up
1621*0Sstevel@tonic-gate 		 */
1622*0Sstevel@tonic-gate 		ls = buildLdapSearch(dn, LDAP_SCOPE_BASE, 0, 0,
1623*0Sstevel@tonic-gate 			"objectclass=*", 0, 0, 0);
1624*0Sstevel@tonic-gate 		if (ls == 0) {
1625*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
1626*0Sstevel@tonic-gate 				"%s: Unable to create ldapSearch "
1627*0Sstevel@tonic-gate 				"request for dn: %s", myself, dn);
1628*0Sstevel@tonic-gate 			return (FAILURE);
1629*0Sstevel@tonic-gate 		}
1630*0Sstevel@tonic-gate 		nr = -1;
1631*0Sstevel@tonic-gate 		rv = ldapSearch(ls, &nr, 0, &rc);
1632*0Sstevel@tonic-gate 		freeLdapSearch(ls);
1633*0Sstevel@tonic-gate 		if (rc == LDAP_SUCCESS) {
1634*0Sstevel@tonic-gate 			val = findVal("nisDomain", rv, mit_ldap);
1635*0Sstevel@tonic-gate 			if (val != NULL) {
1636*0Sstevel@tonic-gate 				/*
1637*0Sstevel@tonic-gate 				 * Yes, nis domain object found. Check
1638*0Sstevel@tonic-gate 				 * to see if the domain names match.
1639*0Sstevel@tonic-gate 				 * If so, we are done. If not, log
1640*0Sstevel@tonic-gate 				 * a warning message, and return SUCCESS.
1641*0Sstevel@tonic-gate 				 */
1642*0Sstevel@tonic-gate 				if (strcasecmp(val, domain) == 0) {
1643*0Sstevel@tonic-gate 					freeRuleValue(rv, nr);
1644*0Sstevel@tonic-gate 					return (SUCCESS);
1645*0Sstevel@tonic-gate 				} else {
1646*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK,
1647*0Sstevel@tonic-gate 						LOG_WARNING,
1648*0Sstevel@tonic-gate 						"%s: Entry (dn: %s) already "
1649*0Sstevel@tonic-gate 						"contains a nis domain name "
1650*0Sstevel@tonic-gate 						"(%s). The domain name (%s) "
1651*0Sstevel@tonic-gate 						"is not added.",
1652*0Sstevel@tonic-gate 						myself, dn, val, domain);
1653*0Sstevel@tonic-gate 					freeRuleValue(rv, nr);
1654*0Sstevel@tonic-gate 					return (SUCCESS);
1655*0Sstevel@tonic-gate 				}
1656*0Sstevel@tonic-gate 			} else {
1657*0Sstevel@tonic-gate 				freeRuleValue(rv, nr);
1658*0Sstevel@tonic-gate 				/*
1659*0Sstevel@tonic-gate 				 * Entry for the 'dn' exists, but it
1660*0Sstevel@tonic-gate 				 * is not a nis domain object yet.
1661*0Sstevel@tonic-gate 				 * Add the nisDoamin attribute and
1662*0Sstevel@tonic-gate 				 * the nisDomainObject objectclass to
1663*0Sstevel@tonic-gate 				 * the entry.
1664*0Sstevel@tonic-gate 				 */
1665*0Sstevel@tonic-gate 				if ((rv = initRuleValue(1, 0)) == 0)
1666*0Sstevel@tonic-gate 					return (FAILURE);
1667*0Sstevel@tonic-gate 
1668*0Sstevel@tonic-gate 				if (addSAttr2RuleValue("nisDomain",
1669*0Sstevel@tonic-gate 						domain, rv) == -1) {
1670*0Sstevel@tonic-gate 					freeRuleValue(rv, 1);
1671*0Sstevel@tonic-gate 					return (FAILURE);
1672*0Sstevel@tonic-gate 				}
1673*0Sstevel@tonic-gate 				rc = ldapModify(dn, rv,
1674*0Sstevel@tonic-gate 					"objectclass=nisDomainObject",
1675*0Sstevel@tonic-gate 					0);
1676*0Sstevel@tonic-gate 				freeRuleValue(rv, 1);
1677*0Sstevel@tonic-gate 				if (rc == LDAP_SUCCESS) {
1678*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK,
1679*0Sstevel@tonic-gate 						LOG_INFO,
1680*0Sstevel@tonic-gate 						"%s: entry (dn: %s) "
1681*0Sstevel@tonic-gate 						"modified to be an "
1682*0Sstevel@tonic-gate 						"nis domain object",
1683*0Sstevel@tonic-gate 						myself, dn);
1684*0Sstevel@tonic-gate 					return (SUCCESS);
1685*0Sstevel@tonic-gate 				} else {
1686*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK,
1687*0Sstevel@tonic-gate 						LOG_ERR,
1688*0Sstevel@tonic-gate 						"%s: unable to modify "
1689*0Sstevel@tonic-gate 						"entry (dn: %s) to be "
1690*0Sstevel@tonic-gate 						"a nis domain object: "
1691*0Sstevel@tonic-gate 						"ldapModify error %d (%s)",
1692*0Sstevel@tonic-gate 						myself, dn, rc,
1693*0Sstevel@tonic-gate 						ldap_err2string(rc));
1694*0Sstevel@tonic-gate 					return (FAILURE);
1695*0Sstevel@tonic-gate 				}
1696*0Sstevel@tonic-gate 			}
1697*0Sstevel@tonic-gate 		} else { /* search for 'dn' failed */
1698*0Sstevel@tonic-gate 			freeRuleValue(rv, nr);
1699*0Sstevel@tonic-gate 
1700*0Sstevel@tonic-gate 			/*
1701*0Sstevel@tonic-gate 			 * It is OK if no such object, otherwise
1702*0Sstevel@tonic-gate 			 * log an error.
1703*0Sstevel@tonic-gate 			 */
1704*0Sstevel@tonic-gate 			if (rc != LDAP_NO_SUCH_OBJECT) {
1705*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
1706*0Sstevel@tonic-gate 					"%s: unable to retrieve "
1707*0Sstevel@tonic-gate 					"entry (dn: %s): "
1708*0Sstevel@tonic-gate 					"ldapSearch error %d (%s)",
1709*0Sstevel@tonic-gate 					myself, dn, rc,
1710*0Sstevel@tonic-gate 					ldap_err2string(rc));
1711*0Sstevel@tonic-gate 				return (FAILURE);
1712*0Sstevel@tonic-gate 			}
1713*0Sstevel@tonic-gate 		}
1714*0Sstevel@tonic-gate 
1715*0Sstevel@tonic-gate 		/*
1716*0Sstevel@tonic-gate 		 * If the 'dn' is actually the naming context of
1717*0Sstevel@tonic-gate 		 * the DIT, we should be able to make it a nis domain
1718*0Sstevel@tonic-gate 		 * object without worrying about missing parent
1719*0Sstevel@tonic-gate 		 * entries. If unable to add the entry for the 'dn'
1720*0Sstevel@tonic-gate 		 * due to missing parent entries, fall through
1721*0Sstevel@tonic-gate 		 * to create them and then add the nis domain object.
1722*0Sstevel@tonic-gate 		 */
1723*0Sstevel@tonic-gate 		if (addNISObject(domain, dn, &add_rc) == SUCCESS)
1724*0Sstevel@tonic-gate 			return (SUCCESS);
1725*0Sstevel@tonic-gate 		else if (add_rc != LDAP_NO_SUCH_OBJECT)
1726*0Sstevel@tonic-gate 			return (FAILURE);
1727*0Sstevel@tonic-gate 	}
1728*0Sstevel@tonic-gate 
1729*0Sstevel@tonic-gate 	/* Create parent */
1730*0Sstevel@tonic-gate 	if (addParent(dn, NULL) == FAILURE)
1731*0Sstevel@tonic-gate 		return (FAILURE);
1732*0Sstevel@tonic-gate 
1733*0Sstevel@tonic-gate 	if (addNISObject(domain, dn, NULL) == FAILURE)
1734*0Sstevel@tonic-gate 		return (FAILURE);
1735*0Sstevel@tonic-gate 
1736*0Sstevel@tonic-gate 	return (SUCCESS);
1737*0Sstevel@tonic-gate }
1738*0Sstevel@tonic-gate 
1739*0Sstevel@tonic-gate suc_code
1740*0Sstevel@tonic-gate addParent(char *dn, char **attr) {
1741*0Sstevel@tonic-gate 	__nis_rule_value_t	*rv;
1742*0Sstevel@tonic-gate 	__nis_ldap_search_t	*ls;
1743*0Sstevel@tonic-gate 	int			rc, nr;
1744*0Sstevel@tonic-gate 	char			*parentdn = 0, *rdn = 0;
1745*0Sstevel@tonic-gate 	char			*myself = "addParent";
1746*0Sstevel@tonic-gate 
1747*0Sstevel@tonic-gate 	/* Obtain parentdn */
1748*0Sstevel@tonic-gate 	if (splitDN(dn, &rdn, &parentdn) == -1)
1749*0Sstevel@tonic-gate 		return (FAILURE);
1750*0Sstevel@tonic-gate 	if (!parentdn) {
1751*0Sstevel@tonic-gate 		sfree(rdn);
1752*0Sstevel@tonic-gate 		return (FAILURE);
1753*0Sstevel@tonic-gate 	}
1754*0Sstevel@tonic-gate 
1755*0Sstevel@tonic-gate 	/* Check if parentdn exists */
1756*0Sstevel@tonic-gate 	ls = buildLdapSearch(parentdn, LDAP_SCOPE_BASE, 0, 0,
1757*0Sstevel@tonic-gate 					"objectclass=*", 0, 0, 0);
1758*0Sstevel@tonic-gate 	if (ls == 0) {
1759*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
1760*0Sstevel@tonic-gate 			"%s: Unable to create ldapSearch request for "
1761*0Sstevel@tonic-gate 			"parent (dn: %s) of (dn: %s)",
1762*0Sstevel@tonic-gate 			myself, parentdn, dn);
1763*0Sstevel@tonic-gate 		sfree(parentdn);
1764*0Sstevel@tonic-gate 		sfree(rdn);
1765*0Sstevel@tonic-gate 		return (FAILURE);
1766*0Sstevel@tonic-gate 	}
1767*0Sstevel@tonic-gate 	nr = -1;
1768*0Sstevel@tonic-gate 	rv = ldapSearch(ls, &nr, 0, &rc);
1769*0Sstevel@tonic-gate 	freeLdapSearch(ls);
1770*0Sstevel@tonic-gate 	freeRuleValue(rv, nr);
1771*0Sstevel@tonic-gate 
1772*0Sstevel@tonic-gate 	/* Create parent if it doesn't exists */
1773*0Sstevel@tonic-gate 	if (rc == LDAP_NO_SUCH_OBJECT) {
1774*0Sstevel@tonic-gate 		if (makeNISObject(0, parentdn) == FAILURE) {
1775*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
1776*0Sstevel@tonic-gate 				"%s: Unable to create parent (dn: %s) of "
1777*0Sstevel@tonic-gate 				"(dn: %s) in the DIT", myself, parentdn, dn);
1778*0Sstevel@tonic-gate 			sfree(parentdn);
1779*0Sstevel@tonic-gate 			sfree(rdn);
1780*0Sstevel@tonic-gate 			return (FAILURE);
1781*0Sstevel@tonic-gate 		}
1782*0Sstevel@tonic-gate 	}
1783*0Sstevel@tonic-gate 	sfree(parentdn);
1784*0Sstevel@tonic-gate 
1785*0Sstevel@tonic-gate 	if (attr && rdn)
1786*0Sstevel@tonic-gate 		*attr = (char *)getObjectClass(rdn);
1787*0Sstevel@tonic-gate 	sfree(rdn);
1788*0Sstevel@tonic-gate 
1789*0Sstevel@tonic-gate 	return (SUCCESS);
1790*0Sstevel@tonic-gate }
1791*0Sstevel@tonic-gate 
1792*0Sstevel@tonic-gate 
1793*0Sstevel@tonic-gate 
1794*0Sstevel@tonic-gate /*
1795*0Sstevel@tonic-gate  * FUNCTION :	is_fatal_error()
1796*0Sstevel@tonic-gate  *
1797*0Sstevel@tonic-gate  * DESCRIPTION:	Works out if a failed mapping operation should be retried.
1798*0Sstevel@tonic-gate  *
1799*0Sstevel@tonic-gate  * INPUTS :	Result code from operation
1800*0Sstevel@tonic-gate  *
1801*0Sstevel@tonic-gate  * OUTPUTS :	TRUE = Fatal error, don't retry.
1802*0Sstevel@tonic-gate  *		FALSE = Temporary error, retry.
1803*0Sstevel@tonic-gate  */
1804*0Sstevel@tonic-gate bool_t
1805*0Sstevel@tonic-gate is_fatal_error(int res)
1806*0Sstevel@tonic-gate {
1807*0Sstevel@tonic-gate 
1808*0Sstevel@tonic-gate 	if (0 > res)
1809*0Sstevel@tonic-gate 		/* An internal mapping error. Not going to go away. */
1810*0Sstevel@tonic-gate 		return (TRUE);
1811*0Sstevel@tonic-gate 
1812*0Sstevel@tonic-gate 	switch (res) {
1813*0Sstevel@tonic-gate 		case (LDAP_PROTOCOL_ERROR):
1814*0Sstevel@tonic-gate 		case (LDAP_TIMELIMIT_EXCEEDED):
1815*0Sstevel@tonic-gate 		case (LDAP_PARTIAL_RESULTS):
1816*0Sstevel@tonic-gate 		case (LDAP_BUSY):
1817*0Sstevel@tonic-gate 		case (LDAP_UNAVAILABLE):
1818*0Sstevel@tonic-gate 		case (LDAP_UNWILLING_TO_PERFORM):
1819*0Sstevel@tonic-gate 		case (LDAP_OTHER):
1820*0Sstevel@tonic-gate 		case (LDAP_SERVER_DOWN):
1821*0Sstevel@tonic-gate 		case (LDAP_LOCAL_ERROR):
1822*0Sstevel@tonic-gate 		case (LDAP_TIMEOUT):
1823*0Sstevel@tonic-gate 		case (LDAP_NO_MEMORY):
1824*0Sstevel@tonic-gate 			/* Probably worth a retry */
1825*0Sstevel@tonic-gate 			return (FALSE);
1826*0Sstevel@tonic-gate 
1827*0Sstevel@tonic-gate 		default:
1828*0Sstevel@tonic-gate 			return (TRUE);
1829*0Sstevel@tonic-gate 	}
1830*0Sstevel@tonic-gate }
1831*0Sstevel@tonic-gate 
1832*0Sstevel@tonic-gate /*
1833*0Sstevel@tonic-gate  * FUNCTION :	addNISObject()
1834*0Sstevel@tonic-gate  *
1835*0Sstevel@tonic-gate  * DESCRIPTION: Add a nis Object in the DIT.
1836*0Sstevel@tonic-gate  *
1837*0Sstevel@tonic-gate  * GIVEN :
1838*0Sstevel@tonic-gate  *		Case 1: 'dn' is NULL
1839*0Sstevel@tonic-gate  *			Error
1840*0Sstevel@tonic-gate  *		Case 2: 'domain' is non-NULL
1841*0Sstevel@tonic-gate  *			Create nisDomainObject with the given information
1842*0Sstevel@tonic-gate  *		Case 3: 'domain' is NULL
1843*0Sstevel@tonic-gate  *			Create an object with the 'dn'
1844*0Sstevel@tonic-gate  *			Here we guess the objectclass attribute, based on
1845*0Sstevel@tonic-gate  *			oc_lookup table
1846*0Sstevel@tonic-gate  *
1847*0Sstevel@tonic-gate  * RETURNS :	SUCCESS = It worked
1848*0Sstevel@tonic-gate  *		FAILURE = There was a problem. If the ldap add
1849*0Sstevel@tonic-gate  *                        operation failed, ldap_rc will be set
1850*0Sstevel@tonic-gate  *			  to the ldap error code.
1851*0Sstevel@tonic-gate  */
1852*0Sstevel@tonic-gate suc_code
1853*0Sstevel@tonic-gate addNISObject(char *domain, char *dn, int *ldap_rc) {
1854*0Sstevel@tonic-gate 	__nis_rule_value_t	*rv;
1855*0Sstevel@tonic-gate 	int			rc;
1856*0Sstevel@tonic-gate 	char			*objClassAttrs = NULL, *attrs;
1857*0Sstevel@tonic-gate 	char			*value, *svalue, *rdn = NULL;
1858*0Sstevel@tonic-gate 	char			*myself = "addNISObject";
1859*0Sstevel@tonic-gate 
1860*0Sstevel@tonic-gate 	if (!dn)
1861*0Sstevel@tonic-gate 		return (FAILURE);
1862*0Sstevel@tonic-gate 
1863*0Sstevel@tonic-gate 	if ((rv = initRuleValue(1, 0)) == 0)
1864*0Sstevel@tonic-gate 		return (FAILURE);
1865*0Sstevel@tonic-gate 
1866*0Sstevel@tonic-gate 	if (ldap_rc)
1867*0Sstevel@tonic-gate 		*ldap_rc = -1;
1868*0Sstevel@tonic-gate 
1869*0Sstevel@tonic-gate 	/*
1870*0Sstevel@tonic-gate 	 * Add name=value pairs from RDN. Although this is not required
1871*0Sstevel@tonic-gate 	 * for SunOne Directory Server, during openldap interoperabilty
1872*0Sstevel@tonic-gate 	 * tests, it was found out that openldap server returned object
1873*0Sstevel@tonic-gate 	 * class violation errors if MUST attributes were not specified
1874*0Sstevel@tonic-gate 	 * explicitly.
1875*0Sstevel@tonic-gate 	 */
1876*0Sstevel@tonic-gate 	if (splitDN(dn, &rdn, 0) == -1)
1877*0Sstevel@tonic-gate 		return (FAILURE);
1878*0Sstevel@tonic-gate 	if (rdn != NULL) {
1879*0Sstevel@tonic-gate 		objClassAttrs = (char *)getObjectClass(rdn);
1880*0Sstevel@tonic-gate 		if (objClassAttrs == NULL) {
1881*0Sstevel@tonic-gate 			sfree(rdn);
1882*0Sstevel@tonic-gate 			return (FAILURE);
1883*0Sstevel@tonic-gate 		}
1884*0Sstevel@tonic-gate 
1885*0Sstevel@tonic-gate 		/*
1886*0Sstevel@tonic-gate 		 * RDN can be composed of multiple name=value pairs
1887*0Sstevel@tonic-gate 		 * concatenated by '+'. Hence, we need to determine each
1888*0Sstevel@tonic-gate 		 * pair and add it to 'rv'
1889*0Sstevel@tonic-gate 		 */
1890*0Sstevel@tonic-gate 		for (value = rdn, svalue = NULL; *value != '\0'; value++) {
1891*0Sstevel@tonic-gate 			if (*value == '+') {
1892*0Sstevel@tonic-gate 				/* Make sure it's not escaped */
1893*0Sstevel@tonic-gate 				if (value == rdn || *(value - 1) != '\\') {
1894*0Sstevel@tonic-gate 					/*
1895*0Sstevel@tonic-gate 					 * We are at the start of the new
1896*0Sstevel@tonic-gate 					 * pair. 'svalue' now contains the
1897*0Sstevel@tonic-gate 					 * value for the previous pair. Add
1898*0Sstevel@tonic-gate 					 * the previous pair to 'rv'
1899*0Sstevel@tonic-gate 					 */
1900*0Sstevel@tonic-gate 					*value = '\0';
1901*0Sstevel@tonic-gate 					if (svalue &&
1902*0Sstevel@tonic-gate 					addSAttr2RuleValue(rdn, svalue, rv)
1903*0Sstevel@tonic-gate 									== -1) {
1904*0Sstevel@tonic-gate 						sfree(rdn);
1905*0Sstevel@tonic-gate 						freeRuleValue(rv, 1);
1906*0Sstevel@tonic-gate 						return (FAILURE);
1907*0Sstevel@tonic-gate 					}
1908*0Sstevel@tonic-gate 					svalue = NULL;
1909*0Sstevel@tonic-gate 					rdn = value + 1;
1910*0Sstevel@tonic-gate 					continue;
1911*0Sstevel@tonic-gate 				}
1912*0Sstevel@tonic-gate 			}
1913*0Sstevel@tonic-gate 
1914*0Sstevel@tonic-gate 			if (*value == '=') {
1915*0Sstevel@tonic-gate 				if (value == rdn || *(value - 1) != '\\') {
1916*0Sstevel@tonic-gate 					/*
1917*0Sstevel@tonic-gate 					 * 'rdn' now contains the name.
1918*0Sstevel@tonic-gate 					 * Whatever follows till the next
1919*0Sstevel@tonic-gate 					 * unescaped '+' or '\0' is the
1920*0Sstevel@tonic-gate 					 * value for this pair.
1921*0Sstevel@tonic-gate 					 */
1922*0Sstevel@tonic-gate 					*value = '\0';
1923*0Sstevel@tonic-gate 					svalue = value + 1;
1924*0Sstevel@tonic-gate 					continue;
1925*0Sstevel@tonic-gate 				}
1926*0Sstevel@tonic-gate 			}
1927*0Sstevel@tonic-gate 		}
1928*0Sstevel@tonic-gate 
1929*0Sstevel@tonic-gate 		/*
1930*0Sstevel@tonic-gate 		 * End of String. Add the previous name=value pair to 'rv'
1931*0Sstevel@tonic-gate 		 */
1932*0Sstevel@tonic-gate 		if (svalue && addSAttr2RuleValue(rdn, svalue, rv) == -1) {
1933*0Sstevel@tonic-gate 			sfree(rdn);
1934*0Sstevel@tonic-gate 			freeRuleValue(rv, 1);
1935*0Sstevel@tonic-gate 			return (FAILURE);
1936*0Sstevel@tonic-gate 		}
1937*0Sstevel@tonic-gate 		sfree(rdn);
1938*0Sstevel@tonic-gate 	} else /* rdn  == NULL */
1939*0Sstevel@tonic-gate 		return (FAILURE);
1940*0Sstevel@tonic-gate 
1941*0Sstevel@tonic-gate 	/* Create the entry */
1942*0Sstevel@tonic-gate 	if (domain) {
1943*0Sstevel@tonic-gate 		if (addSAttr2RuleValue("nisDomain", domain, rv) == -1) {
1944*0Sstevel@tonic-gate 			freeRuleValue(rv, 1);
1945*0Sstevel@tonic-gate 			return (FAILURE);
1946*0Sstevel@tonic-gate 		}
1947*0Sstevel@tonic-gate 		attrs = scat(myself, F, "objectclass=nisdomainobject,",
1948*0Sstevel@tonic-gate 					objClassAttrs);
1949*0Sstevel@tonic-gate 		if (!attrs) {
1950*0Sstevel@tonic-gate 			freeRuleValue(rv, 1);
1951*0Sstevel@tonic-gate 			return (FAILURE);
1952*0Sstevel@tonic-gate 		}
1953*0Sstevel@tonic-gate 		rc = ldapAdd(dn, rv, attrs, 0);
1954*0Sstevel@tonic-gate 		sfree(attrs);
1955*0Sstevel@tonic-gate 	} else {
1956*0Sstevel@tonic-gate 		rc = ldapAdd(dn, rv, objClassAttrs, 0);
1957*0Sstevel@tonic-gate 	}
1958*0Sstevel@tonic-gate 
1959*0Sstevel@tonic-gate 	if (rc == LDAP_SUCCESS)
1960*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
1961*0Sstevel@tonic-gate 				"%s: Entry (dn: %s) added to DIT",
1962*0Sstevel@tonic-gate 				myself, dn);
1963*0Sstevel@tonic-gate 	else if (rc == LDAP_ALREADY_EXISTS)
1964*0Sstevel@tonic-gate 		/* Treat this as success */
1965*0Sstevel@tonic-gate 		rc = LDAP_SUCCESS;
1966*0Sstevel@tonic-gate 	else
1967*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
1968*0Sstevel@tonic-gate 				"%s: ldapAdd error %d (%s) for (dn: %s)",
1969*0Sstevel@tonic-gate 				myself, rc, ldap_err2string(rc), dn);
1970*0Sstevel@tonic-gate 
1971*0Sstevel@tonic-gate 	freeRuleValue(rv, 1);
1972*0Sstevel@tonic-gate 	if (ldap_rc)
1973*0Sstevel@tonic-gate 		*ldap_rc = rc;
1974*0Sstevel@tonic-gate 	return ((rc == LDAP_SUCCESS)?SUCCESS:FAILURE);
1975*0Sstevel@tonic-gate }
1976