xref: /onnv-gate/usr/src/lib/libnisdb/yptol/dit_access.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 2004 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 top level functions to read/write to the DIT. These
31*0Sstevel@tonic-gate  *		are the API between the shim and the mapping system.
32*0Sstevel@tonic-gate  *		Things calling these should have no knowledge of LDAP. Things
33*0Sstevel@tonic-gate  *		called by them should have no knowledge of NIS.
34*0Sstevel@tonic-gate  *
35*0Sstevel@tonic-gate  *		Error handling here may appear to be limited but, because the
36*0Sstevel@tonic-gate  *		NIS protocol cannot carry meaningful information about why a
37*0Sstevel@tonic-gate  *		N2L operation failed, functions that don't work log
38*0Sstevel@tonic-gate  *		an error and then just return FAILURE.
39*0Sstevel@tonic-gate  *
40*0Sstevel@tonic-gate  */
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate /*
43*0Sstevel@tonic-gate  * Includes. WE WANT TO USE REAL DBM FUNCTIONS SO DO NOT INCLUDE SHIM_HOOKS.H.
44*0Sstevel@tonic-gate  */
45*0Sstevel@tonic-gate #include <unistd.h>
46*0Sstevel@tonic-gate #include <syslog.h>
47*0Sstevel@tonic-gate #include <ndbm.h>
48*0Sstevel@tonic-gate #include <sys/systeminfo.h>
49*0Sstevel@tonic-gate #include <string.h>
50*0Sstevel@tonic-gate #include <lber.h>
51*0Sstevel@tonic-gate #include <ldap.h>
52*0Sstevel@tonic-gate #include <errno.h>
53*0Sstevel@tonic-gate #include "ypsym.h"
54*0Sstevel@tonic-gate #include "ypdefs.h"
55*0Sstevel@tonic-gate #include "shim.h"
56*0Sstevel@tonic-gate #include "../ldap_structs.h"
57*0Sstevel@tonic-gate #include "../ldap_parse.h"
58*0Sstevel@tonic-gate #include "../nisdb_ldap.h"
59*0Sstevel@tonic-gate #include "../ldap_util.h"
60*0Sstevel@tonic-gate #include "../ldap_op.h"
61*0Sstevel@tonic-gate #include "../ldap_attr.h"
62*0Sstevel@tonic-gate #include "../nis_parse_ldap_conf.h"
63*0Sstevel@tonic-gate #include "../nisdb_mt.h"
64*0Sstevel@tonic-gate #include "yptol.h"
65*0Sstevel@tonic-gate #include "dit_access_utils.h"
66*0Sstevel@tonic-gate #include "stdio.h"
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate /* Enable standard YP code features defined in ypdefs.h */
69*0Sstevel@tonic-gate USE_YP_PREFIX
70*0Sstevel@tonic-gate USE_YP_MASTER_NAME
71*0Sstevel@tonic-gate USE_YP_LAST_MODIFIED
72*0Sstevel@tonic-gate USE_YP_INPUT_FILE
73*0Sstevel@tonic-gate USE_YP_OUTPUT_NAME
74*0Sstevel@tonic-gate USE_YP_DOMAIN_NAME
75*0Sstevel@tonic-gate USE_YP_SECURE
76*0Sstevel@tonic-gate USE_YP_INTERDOMAIN
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate /*
79*0Sstevel@tonic-gate  * Decs
80*0Sstevel@tonic-gate  */
81*0Sstevel@tonic-gate suc_code add_special_entries(DBM *, map_ctrl *, bool_t *);
82*0Sstevel@tonic-gate void free_null_terminated_list(char **list);
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate /*
86*0Sstevel@tonic-gate  * FUNCTION:    is_yptol_mode();
87*0Sstevel@tonic-gate  *
88*0Sstevel@tonic-gate  * DESCRIPTION:	Determines if we should run in N2L or traditional mode based
89*0Sstevel@tonic-gate  *		on the presence of the N2L mapping file. If there are problems
90*0Sstevel@tonic-gate  *		with the file, e.g. unreadable, this will be picked up latter.
91*0Sstevel@tonic-gate  *
92*0Sstevel@tonic-gate  * INPUTS:     	Nothing
93*0Sstevel@tonic-gate  *
94*0Sstevel@tonic-gate  * OUTPUTS:   	TRUE = Run in N2L mode
95*0Sstevel@tonic-gate  *		FALSE = Run in traditional mode.
96*0Sstevel@tonic-gate  */
97*0Sstevel@tonic-gate bool_t
98*0Sstevel@tonic-gate is_yptol_mode()
99*0Sstevel@tonic-gate {
100*0Sstevel@tonic-gate 	struct stat filestat;
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 	if (stat(YP_DEFAULTCONFFILE, &filestat) != -1)
103*0Sstevel@tonic-gate 		return (TRUE);
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 	return (FALSE);
106*0Sstevel@tonic-gate }
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate /*
109*0Sstevel@tonic-gate  * FUNCTION:    read_from_dit();
110*0Sstevel@tonic-gate  *
111*0Sstevel@tonic-gate  * DESCRIPTION:	Read (i.e. get and map) a single NIS entry from the LDAP DIT.
112*0Sstevel@tonic-gate  *		Also handles retry attempts, on failure, and interpretation of
113*0Sstevel@tonic-gate  *		internal error codes.
114*0Sstevel@tonic-gate  *
115*0Sstevel@tonic-gate  * INPUTS:     	Map name (unqualified)
116*0Sstevel@tonic-gate  *		Domain name
117*0Sstevel@tonic-gate  *		Entry key
118*0Sstevel@tonic-gate  *		Pointer to return location
119*0Sstevel@tonic-gate  *
120*0Sstevel@tonic-gate  * OUTPUTS:   	If successful DBM datum containing result.
121*0Sstevel@tonic-gate  *		On error DBM datum pointing to NULL and, if the cached value
122*0Sstevel@tonic-gate  *		is not to be used, an error code.
123*0Sstevel@tonic-gate  */
124*0Sstevel@tonic-gate int
125*0Sstevel@tonic-gate read_from_dit(char *map, char *domain, datum *key, datum *value)
126*0Sstevel@tonic-gate {
127*0Sstevel@tonic-gate 	int count;
128*0Sstevel@tonic-gate 	int res;
129*0Sstevel@tonic-gate 	__nisdb_retry_t	*retrieveRetry;
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 	/* Initialize tsd */
132*0Sstevel@tonic-gate 	__nisdb_get_tsd()->domainContext = 0;
133*0Sstevel@tonic-gate 	__nisdb_get_tsd()->escapeFlag = '\0';
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	for (count = 0; count < ypDomains.numDomains; count++) {
136*0Sstevel@tonic-gate 		if (0 == ypDomains.domainLabels[count])
137*0Sstevel@tonic-gate 			continue;
138*0Sstevel@tonic-gate 		if (0 == strcasecmp(domain, ypDomains.domainLabels[count])) {
139*0Sstevel@tonic-gate 			__nisdb_get_tsd()->domainContext =
140*0Sstevel@tonic-gate 					ypDomains.domains[count];
141*0Sstevel@tonic-gate 			break;
142*0Sstevel@tonic-gate 		}
143*0Sstevel@tonic-gate 	}
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 	retrieveRetry = &ldapDBTableMapping.retrieveErrorRetry;
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	/* Loop 'attempts' times of forever if -1 */
148*0Sstevel@tonic-gate 	for (count = retrieveRetry->attempts; (0 <= count) ||
149*0Sstevel@tonic-gate 			(-1 == retrieveRetry->attempts); count --) {
150*0Sstevel@tonic-gate 		if (TRUE == singleReadFromDIT(map, domain, key, value, &res))
151*0Sstevel@tonic-gate 			/* It worked, return value irrelevant */
152*0Sstevel@tonic-gate 			return (0);
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 		if (LDAP_TIMEOUT == res) { /* Exceeded search timeout */
155*0Sstevel@tonic-gate 			value->dptr = NULL;
156*0Sstevel@tonic-gate 			return (0);
157*0Sstevel@tonic-gate 		}
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 		if (is_fatal_error(res))
160*0Sstevel@tonic-gate 			break;
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 		/*
163*0Sstevel@tonic-gate 		 * Didn't work. If not the special case where no repeats are
164*0Sstevel@tonic-gate 		 * done sleep.
165*0Sstevel@tonic-gate 		 */
166*0Sstevel@tonic-gate 		if (0 != retrieveRetry->attempts)
167*0Sstevel@tonic-gate 			(void) poll(NULL, 0, retrieveRetry->timeout*1000);
168*0Sstevel@tonic-gate 	}
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate 	/* Make sure returned pointer is NULL */
171*0Sstevel@tonic-gate 	value->dptr = NULL;
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 	/* If we get here access failed work out what to return */
174*0Sstevel@tonic-gate 	if (ldapDBTableMapping.retrieveError == use_cached)
175*0Sstevel@tonic-gate 		return (0);
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	return (res);
178*0Sstevel@tonic-gate }
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate /*
181*0Sstevel@tonic-gate  * FUNCTION:    write_to_dit();
182*0Sstevel@tonic-gate  *
183*0Sstevel@tonic-gate  * DESCRIPTION:	Maps and writes a NIS entry to the LDAP DIT.
184*0Sstevel@tonic-gate  *		Also handles retry attempts, on failure, and interpretation of
185*0Sstevel@tonic-gate  *		internal error codes.
186*0Sstevel@tonic-gate  *
187*0Sstevel@tonic-gate  * INPUTS:     	Pointer to (unqualified) map name
188*0Sstevel@tonic-gate  *		Pointer to domain name
189*0Sstevel@tonic-gate  *		The entries key
190*0Sstevel@tonic-gate  *		What to write
191*0Sstevel@tonic-gate  *		Replace flag indicating
192*0Sstevel@tonic-gate  *			TRUE = Replace (overwrite) any existing entries
193*0Sstevel@tonic-gate  *			FALSE = Return error if there are existing entries
194*0Sstevel@tonic-gate  *		Flag indicating if we should tolerate mapping errors.
195*0Sstevel@tonic-gate  *
196*0Sstevel@tonic-gate  * OUTPUTS:   	SUCCESS = Write was successful
197*0Sstevel@tonic-gate  *		FAILURE = Write failed
198*0Sstevel@tonic-gate  *
199*0Sstevel@tonic-gate  */
200*0Sstevel@tonic-gate suc_code
201*0Sstevel@tonic-gate write_to_dit(char *map, char *domain, datum key, datum value,
202*0Sstevel@tonic-gate 					bool_t replace, bool_t ignore_map_errs)
203*0Sstevel@tonic-gate {
204*0Sstevel@tonic-gate 	int count;
205*0Sstevel@tonic-gate 	int res;
206*0Sstevel@tonic-gate 	__nisdb_retry_t	*storeRetry = &ldapDBTableMapping.storeErrorRetry;
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	/* Initialize tsd */
209*0Sstevel@tonic-gate 	__nisdb_get_tsd()->domainContext = 0;
210*0Sstevel@tonic-gate 	__nisdb_get_tsd()->escapeFlag = '\0';
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	for (count = 0; count < ypDomains.numDomains; count++) {
213*0Sstevel@tonic-gate 		if (0 == ypDomains.domainLabels[count])
214*0Sstevel@tonic-gate 			continue;
215*0Sstevel@tonic-gate 		if (0 == strcasecmp(domain, ypDomains.domainLabels[count])) {
216*0Sstevel@tonic-gate 			__nisdb_get_tsd()->domainContext =
217*0Sstevel@tonic-gate 						ypDomains.domains[count];
218*0Sstevel@tonic-gate 			break;
219*0Sstevel@tonic-gate 		}
220*0Sstevel@tonic-gate 	}
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	storeRetry = &ldapDBTableMapping.storeErrorRetry;
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	/* Loop 'attempts' times of forever if -1 */
225*0Sstevel@tonic-gate 	for (count = storeRetry->attempts; (0 <= count) ||
226*0Sstevel@tonic-gate 				(-1 == storeRetry->attempts); count --) {
227*0Sstevel@tonic-gate 		res = singleWriteToDIT(map, domain, &key, &value, replace);
228*0Sstevel@tonic-gate 		if (LDAP_SUCCESS == res)
229*0Sstevel@tonic-gate 			return (SUCCESS);
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 		if (is_fatal_error(res)) {
232*0Sstevel@tonic-gate 			/*
233*0Sstevel@tonic-gate 			 * The mapping failed and will fail again if it is
234*0Sstevel@tonic-gate 			 * retried. However there are some cases where an
235*0Sstevel@tonic-gate 			 * actual mapping fault (rather than a LDAP problem)
236*0Sstevel@tonic-gate 			 * may be ignored.
237*0Sstevel@tonic-gate 			 */
238*0Sstevel@tonic-gate 			if (ignore_map_errs) {
239*0Sstevel@tonic-gate 				switch (res) {
240*0Sstevel@tonic-gate 					case LDAP_INVALID_DN_SYNTAX:
241*0Sstevel@tonic-gate 					case LDAP_OBJECT_CLASS_VIOLATION:
242*0Sstevel@tonic-gate 					case LDAP_NOT_ALLOWED_ON_RDN:
243*0Sstevel@tonic-gate 					case MAP_NAMEFIELD_MATCH_ERROR:
244*0Sstevel@tonic-gate 					case MAP_NO_DN:
245*0Sstevel@tonic-gate 						return (SUCCESS);
246*0Sstevel@tonic-gate 					default:
247*0Sstevel@tonic-gate 						break;
248*0Sstevel@tonic-gate 				}
249*0Sstevel@tonic-gate 			}
250*0Sstevel@tonic-gate 			return (FAILURE);
251*0Sstevel@tonic-gate 		}
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 		if (ldapDBTableMapping.storeError != sto_retry)
254*0Sstevel@tonic-gate 			return (FAILURE);
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 		/*
257*0Sstevel@tonic-gate 		 * Didn't work. If not the special case where no repeats are
258*0Sstevel@tonic-gate 		 * done sleep.
259*0Sstevel@tonic-gate 		 */
260*0Sstevel@tonic-gate 		if (0 != storeRetry->attempts)
261*0Sstevel@tonic-gate 			(void) poll(NULL, 0, storeRetry->timeout*1000);
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	}
264*0Sstevel@tonic-gate 	return (FAILURE);
265*0Sstevel@tonic-gate }
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate /*
268*0Sstevel@tonic-gate  * FUNCTION :	get_ttl_value()
269*0Sstevel@tonic-gate  *
270*0Sstevel@tonic-gate  * DESCRIPTION:	Get the TTL value, derived from mapping file or DIT, for a
271*0Sstevel@tonic-gate  *		entry.
272*0Sstevel@tonic-gate  *
273*0Sstevel@tonic-gate  * GIVEN :	Pointer to map
274*0Sstevel@tonic-gate  *		A flag indication if TTL should be max, min or random
275*0Sstevel@tonic-gate  *
276*0Sstevel@tonic-gate  * RETURNS :	TTL value in seconds.
277*0Sstevel@tonic-gate  *		-1 on failure
278*0Sstevel@tonic-gate  */
279*0Sstevel@tonic-gate int
280*0Sstevel@tonic-gate get_ttl_value(map_ctrl *map, TTL_TYPE type)
281*0Sstevel@tonic-gate {
282*0Sstevel@tonic-gate 	__nis_table_mapping_t *table_map;
283*0Sstevel@tonic-gate 	struct timeval ret;
284*0Sstevel@tonic-gate 	int interval, res;
285*0Sstevel@tonic-gate 	char *myself = "get_ttl_value";
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	/*  Get the mapping structure corresponding to `map.domain' */
288*0Sstevel@tonic-gate 	table_map = mappingFromMap(map->map_name, map->domain, &res);
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	if (0 == table_map) {
291*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
292*0Sstevel@tonic-gate 			"Get TTL request could not access map %s in domain %s "
293*0Sstevel@tonic-gate 			"(error %d)", map->map_name, map->domain, res);
294*0Sstevel@tonic-gate 		return (-1);
295*0Sstevel@tonic-gate 	}
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 	switch (type) {
298*0Sstevel@tonic-gate 		case TTL_MAX:
299*0Sstevel@tonic-gate 			return (table_map->initTtlHi);
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 		case TTL_MIN:
302*0Sstevel@tonic-gate 			return (table_map->initTtlLo);
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 		default:
305*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
306*0Sstevel@tonic-gate 			"%s passed illegal TTL type (%d)", myself, type);
307*0Sstevel@tonic-gate 			/* If unknown TTL type drop through to TTL_RAND */
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 		case TTL_RAND:
310*0Sstevel@tonic-gate 			interval = table_map->initTtlHi - table_map->initTtlLo;
311*0Sstevel@tonic-gate 			if (0 >= interval)
312*0Sstevel@tonic-gate 				return (table_map->initTtlLo);
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 			/*
315*0Sstevel@tonic-gate 			 * Must get a random value. We assume srand48() got
316*0Sstevel@tonic-gate 			 * called at initialization.
317*0Sstevel@tonic-gate 			 */
318*0Sstevel@tonic-gate 			return (lrand48() % interval);
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 		case TTL_RUNNING:
321*0Sstevel@tonic-gate 			return (table_map->ttl);
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	}
325*0Sstevel@tonic-gate }
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate /*
328*0Sstevel@tonic-gate  * FUNCTION :	get_mapping_domain_list()
329*0Sstevel@tonic-gate  *
330*0Sstevel@tonic-gate  * DESCRIPTION:	Gets a list of domain names specified, by nisLDAPdomainContext
331*0Sstevel@tonic-gate  *		attributes, in the mapping file. This is used only for initial
332*0Sstevel@tonic-gate  *		DIT setup. Once the DIT has been set up get_domain_list() is
333*0Sstevel@tonic-gate  *		used instead.
334*0Sstevel@tonic-gate  *
335*0Sstevel@tonic-gate  * GIVEN :	Pointer returned array.
336*0Sstevel@tonic-gate  *
337*0Sstevel@tonic-gate  * RETURNS :	Number of element in returned array.
338*0Sstevel@tonic-gate  *		Array of elements this is in static memory
339*0Sstevel@tonic-gate  *		and must not be freed by the caller.
340*0Sstevel@tonic-gate  */
341*0Sstevel@tonic-gate int
342*0Sstevel@tonic-gate get_mapping_domain_list(char ***ptr)
343*0Sstevel@tonic-gate {
344*0Sstevel@tonic-gate 	*ptr = ypDomains.domainLabels;
345*0Sstevel@tonic-gate 	return (ypDomains.numDomains);
346*0Sstevel@tonic-gate }
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate /*
349*0Sstevel@tonic-gate  * FUNCTION :	get_mapping_yppasswdd_domain_list()
350*0Sstevel@tonic-gate  *
351*0Sstevel@tonic-gate  * DESCRIPTION:	Gets a list of domain names specified, by the
352*0Sstevel@tonic-gate  *		nisLDAPyppasswddDomains attribute, in the mapping file. This
353*0Sstevel@tonic-gate  *		is the list of domains for which passwords should be changed.
354*0Sstevel@tonic-gate  *
355*0Sstevel@tonic-gate  * GIVEN :	Pointer returned array
356*0Sstevel@tonic-gate  *
357*0Sstevel@tonic-gate  * RETURNS :	Number of element in returned array.
358*0Sstevel@tonic-gate  *		0 if no nisLDAPyppasswddDomains attribute is present.
359*0Sstevel@tonic-gate  *		Array of elements this is in static memory
360*0Sstevel@tonic-gate  *		and must not be freed by the caller.
361*0Sstevel@tonic-gate  */
362*0Sstevel@tonic-gate int
363*0Sstevel@tonic-gate get_mapping_yppasswdd_domain_list(char ***ptr)
364*0Sstevel@tonic-gate {
365*0Sstevel@tonic-gate 	*ptr = ypDomains.yppasswddDomainLabels;
366*0Sstevel@tonic-gate 	return (ypDomains.numYppasswdd);
367*0Sstevel@tonic-gate }
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate /*
370*0Sstevel@tonic-gate  * FUNCTION :	free_map_list()
371*0Sstevel@tonic-gate  *
372*0Sstevel@tonic-gate  * DESCRIPTION:	Frees a map list.
373*0Sstevel@tonic-gate  *
374*0Sstevel@tonic-gate  * GIVEN :	Pointer to the map list.
375*0Sstevel@tonic-gate  *
376*0Sstevel@tonic-gate  * RETURNS :	Nothing
377*0Sstevel@tonic-gate  */
378*0Sstevel@tonic-gate void
379*0Sstevel@tonic-gate free_map_list(char **map_list)
380*0Sstevel@tonic-gate {
381*0Sstevel@tonic-gate 	free_null_terminated_list(map_list);
382*0Sstevel@tonic-gate }
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate /*
385*0Sstevel@tonic-gate  * FUNCTION :	get_passwd_list()
386*0Sstevel@tonic-gate  *
387*0Sstevel@tonic-gate  * DESCRIPTION:	Gets a list of either passwd or passwd.adjunct map files
388*0Sstevel@tonic-gate  *		defined in the mapping file. These are the files which have
389*0Sstevel@tonic-gate  *		'magic' nisLDAPdatabaseIdMapping entries aliasing them to
390*0Sstevel@tonic-gate  *		passwd or passwd.adjunct. This function is required so that
391*0Sstevel@tonic-gate  *		yppasswdd can work out which maps to synchronize with any
392*0Sstevel@tonic-gate  *		password changes.
393*0Sstevel@tonic-gate  *
394*0Sstevel@tonic-gate  *		This information is not currently stored by the parser but
395*0Sstevel@tonic-gate  *		we can recover it from the hash table. This makes hard work but
396*0Sstevel@tonic-gate  *		passwords should not be changed very frequently
397*0Sstevel@tonic-gate  *
398*0Sstevel@tonic-gate  * GIVEN :	Flag indicating if a list is required for passwd or
399*0Sstevel@tonic-gate  *		passwd.adjunct
400*0Sstevel@tonic-gate  *		Domain to return the list for.
401*0Sstevel@tonic-gate  *
402*0Sstevel@tonic-gate  * RETURNS :	Null terminated list of map names in malloced memory. To be
403*0Sstevel@tonic-gate  *		freed by caller. (Possibly empty if no passwd maps found)
404*0Sstevel@tonic-gate  *		NULL on error
405*0Sstevel@tonic-gate  */
406*0Sstevel@tonic-gate #define	ARRAY_CHUNK	10
407*0Sstevel@tonic-gate char **
408*0Sstevel@tonic-gate get_passwd_list(bool_t adjunct, char *domain)
409*0Sstevel@tonic-gate {
410*0Sstevel@tonic-gate 	char *myself = "get_passwd_list";
411*0Sstevel@tonic-gate 	__nis_hash_item_mt *it;
412*0Sstevel@tonic-gate 	int	i, size;
413*0Sstevel@tonic-gate 	char 	*end_ptr, *copy_ptr;
414*0Sstevel@tonic-gate 	char	*target;	/* What we are looking for */
415*0Sstevel@tonic-gate 	int	target_len;
416*0Sstevel@tonic-gate 	int	domain_len;
417*0Sstevel@tonic-gate 	char	**res;		/* Result array */
418*0Sstevel@tonic-gate 	char	**res_old;	/* Old value of res during realloc */
419*0Sstevel@tonic-gate 	int	array_size;	/* Current malloced size */
420*0Sstevel@tonic-gate 	int	res_count = 0;	/* Current result count */
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	/*
423*0Sstevel@tonic-gate 	 * Always need an array even if just for terminator. Normally one
424*0Sstevel@tonic-gate 	 * chunk will be enough.
425*0Sstevel@tonic-gate 	 */
426*0Sstevel@tonic-gate 	res = am(myself, ARRAY_CHUNK * sizeof (char *));
427*0Sstevel@tonic-gate 	if (NULL == res)
428*0Sstevel@tonic-gate 		return (NULL);
429*0Sstevel@tonic-gate 	array_size = ARRAY_CHUNK;
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	/* Set up target */
432*0Sstevel@tonic-gate 	if (adjunct)
433*0Sstevel@tonic-gate 		target = PASSWD_ADJUNCT_PREFIX;
434*0Sstevel@tonic-gate 	else
435*0Sstevel@tonic-gate 		target = PASSWD_PREFIX;
436*0Sstevel@tonic-gate 	target_len = strlen(target);
437*0Sstevel@tonic-gate 	domain_len = strlen(domain);
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	/* Work out hash table length */
440*0Sstevel@tonic-gate 	size = sizeof (ldapMappingList.keys) / sizeof (ldapMappingList.keys[0]);
441*0Sstevel@tonic-gate 	/* For all hash table entries */
442*0Sstevel@tonic-gate 	for (i = 0; i < size; i++) {
443*0Sstevel@tonic-gate 		/* Walk linked list for this hash table entry */
444*0Sstevel@tonic-gate 		for (it = ldapMappingList.keys[i]; NULL != it; it = it->next) {
445*0Sstevel@tonic-gate 			/* Check right map */
446*0Sstevel@tonic-gate 			if ((target_len + domain_len + 1) > strlen(it->name))
447*0Sstevel@tonic-gate 				continue;
448*0Sstevel@tonic-gate 			if (0 != strncmp(it->name, target, target_len))
449*0Sstevel@tonic-gate 				continue;
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 			/* Check right domain (minus trailing dot) */
452*0Sstevel@tonic-gate 			if (strlen(domain) >= strlen(it->name))
453*0Sstevel@tonic-gate 				continue;
454*0Sstevel@tonic-gate 			end_ptr = it->name + strlen(it->name) -
455*0Sstevel@tonic-gate 							strlen(domain) - 1;
456*0Sstevel@tonic-gate 			if (',' != *(end_ptr - 1))
457*0Sstevel@tonic-gate 				continue;
458*0Sstevel@tonic-gate 			if (0 != strncmp(end_ptr, domain, strlen(domain)))
459*0Sstevel@tonic-gate 				continue;
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 			/* Check if we need to enlarge array */
462*0Sstevel@tonic-gate 			if ((res_count + 1) >= array_size) {
463*0Sstevel@tonic-gate 				array_size += ARRAY_CHUNK;
464*0Sstevel@tonic-gate 				res_old = res;
465*0Sstevel@tonic-gate 				res = realloc(res, array_size *
466*0Sstevel@tonic-gate 							sizeof (char *));
467*0Sstevel@tonic-gate 				if (NULL == res) {
468*0Sstevel@tonic-gate 					res_old[res_count] = NULL;
469*0Sstevel@tonic-gate 					free_passwd_list(res_old);
470*0Sstevel@tonic-gate 					return (NULL);
471*0Sstevel@tonic-gate 				}
472*0Sstevel@tonic-gate 			}
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 			/* What we really need is strndup() */
475*0Sstevel@tonic-gate 			res[res_count] = am(myself, end_ptr - it->name + 1);
476*0Sstevel@tonic-gate 			if (NULL == res[res_count]) {
477*0Sstevel@tonic-gate 				free_passwd_list(res);
478*0Sstevel@tonic-gate 				return (NULL);
479*0Sstevel@tonic-gate 			}
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 			/* Copy from start to end_ptr */
482*0Sstevel@tonic-gate 			memcpy(res[res_count], it->name, end_ptr-it->name - 1);
483*0Sstevel@tonic-gate 			res_count ++;
484*0Sstevel@tonic-gate 		}
485*0Sstevel@tonic-gate 	}
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	/* Terminate array */
488*0Sstevel@tonic-gate 	res[res_count] = NULL;
489*0Sstevel@tonic-gate 	return (res);
490*0Sstevel@tonic-gate }
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate /*
493*0Sstevel@tonic-gate  * FUNCTION :	free_passwd_list()
494*0Sstevel@tonic-gate  *
495*0Sstevel@tonic-gate  * DESCRIPTION:	Frees a password list obtained with get_passwd_list()
496*0Sstevel@tonic-gate  *
497*0Sstevel@tonic-gate  * INPUTS :	Address of list to free.
498*0Sstevel@tonic-gate  *
499*0Sstevel@tonic-gate  * OUTPUTS :	Nothing
500*0Sstevel@tonic-gate  */
501*0Sstevel@tonic-gate void
502*0Sstevel@tonic-gate free_passwd_list(char **list)
503*0Sstevel@tonic-gate {
504*0Sstevel@tonic-gate 	free_null_terminated_list(list);
505*0Sstevel@tonic-gate }
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate /*
508*0Sstevel@tonic-gate  * FUNCTION :	free_null_terminated_list()
509*0Sstevel@tonic-gate  *
510*0Sstevel@tonic-gate  * DESCRIPTION:	Frees a generic null terminated list.
511*0Sstevel@tonic-gate  *
512*0Sstevel@tonic-gate  * INPUTS :	Address of list to free.
513*0Sstevel@tonic-gate  *
514*0Sstevel@tonic-gate  * OUTPUTS :	Nothing
515*0Sstevel@tonic-gate  */
516*0Sstevel@tonic-gate void
517*0Sstevel@tonic-gate free_null_terminated_list(char **list)
518*0Sstevel@tonic-gate {
519*0Sstevel@tonic-gate 	int index;
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 	/* Free all the strings */
522*0Sstevel@tonic-gate 	for (index = 0; NULL != list[index]; index ++)
523*0Sstevel@tonic-gate 		sfree(list[index]);
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 	/* Free the array */
526*0Sstevel@tonic-gate 	sfree(list);
527*0Sstevel@tonic-gate }
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate /*
531*0Sstevel@tonic-gate  * FUNCTION :	add_special_entries()
532*0Sstevel@tonic-gate  *
533*0Sstevel@tonic-gate  * DESCRIPTION:	Adds the special (YP_*) entries to a map.
534*0Sstevel@tonic-gate  *
535*0Sstevel@tonic-gate  *		Part of dit_access because requires access to the mapping
536*0Sstevel@tonic-gate  *		file in order to work out if secure and interdomain entries
537*0Sstevel@tonic-gate  *		should be created.
538*0Sstevel@tonic-gate  *
539*0Sstevel@tonic-gate  * GIVEN :	Pointer to an open, temporary, DBM file
540*0Sstevel@tonic-gate  *		Pointer to map information (do not use DBM fields).
541*0Sstevel@tonic-gate  *		Pointer to a location in which to return security flag
542*0Sstevel@tonic-gate  *
543*0Sstevel@tonic-gate  * RETURNS :	SUCCESS = All entries created
544*0Sstevel@tonic-gate  *		FAILURE = Some entries not created
545*0Sstevel@tonic-gate  */
546*0Sstevel@tonic-gate suc_code
547*0Sstevel@tonic-gate add_special_entries(DBM *db, map_ctrl *map, bool_t *secure_flag)
548*0Sstevel@tonic-gate {
549*0Sstevel@tonic-gate 	char local_host[MAX_MASTER_NAME];
550*0Sstevel@tonic-gate 	char time_string[MAX_ASCII_ORDER_NUMBER_LENGTH];
551*0Sstevel@tonic-gate 	struct timeval	now;
552*0Sstevel@tonic-gate 	__nis_table_mapping_t *table_map;
553*0Sstevel@tonic-gate 	int res;
554*0Sstevel@tonic-gate 
555*0Sstevel@tonic-gate 	/* Last modified time is now */
556*0Sstevel@tonic-gate 	update_timestamp(db);
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 	/* Add domain name */
559*0Sstevel@tonic-gate 	addpair(db, yp_domain_name, map->domain);
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 	/* For N2L input and output file are meaningless */
562*0Sstevel@tonic-gate 	/* addpair(db, yp_input_file, infilename); */
563*0Sstevel@tonic-gate 	/* addpair(db, yp_output_file, outfilename); */
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	/* For N2L mode local machine is always the master */
566*0Sstevel@tonic-gate 	sysinfo(SI_HOSTNAME, local_host, sizeof (local_host));
567*0Sstevel@tonic-gate 	addpair(db, yp_master_name, local_host);
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate 	/*  Get the mapping structure corresponding to `map.domain' */
570*0Sstevel@tonic-gate 	table_map = mappingFromMap(map->map_name, map->domain, &res);
571*0Sstevel@tonic-gate 	if (0 == table_map)
572*0Sstevel@tonic-gate 		return (FAILURE);
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate 	/* Add secure and interdomain flags if required */
575*0Sstevel@tonic-gate 	if (table_map->securemap_flag) {
576*0Sstevel@tonic-gate 		addpair(db, yp_secure, "");
577*0Sstevel@tonic-gate 		*secure_flag = TRUE;
578*0Sstevel@tonic-gate 	} else {
579*0Sstevel@tonic-gate 		*secure_flag = FALSE;
580*0Sstevel@tonic-gate 	}
581*0Sstevel@tonic-gate 	if (table_map->usedns_flag)
582*0Sstevel@tonic-gate 		addpair(db, yp_interdomain, "");
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	return (SUCCESS);
585*0Sstevel@tonic-gate }
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate /*
588*0Sstevel@tonic-gate  * FUNCTION:	update_map_from_dit()
589*0Sstevel@tonic-gate  *
590*0Sstevel@tonic-gate  * DESCRIPTION:	Core code called to update an entire map.
591*0Sstevel@tonic-gate  *		Information is recovered from LDAP and used to build a duplicate
592*0Sstevel@tonic-gate  *		copy of the live maps. When this is complete the maps are
593*0Sstevel@tonic-gate  *		locked and then overwritten by the new copy.
594*0Sstevel@tonic-gate  *
595*0Sstevel@tonic-gate  * INPUTS:	map_ctrl containing lots of information about the map and a
596*0Sstevel@tonic-gate  *		pointer to it's lock which will be required.
597*0Sstevel@tonic-gate  *		Flag indicating if progress logging is required.
598*0Sstevel@tonic-gate  *
599*0Sstevel@tonic-gate  * OUTPUTS:	SUCCESS = Map updated
600*0Sstevel@tonic-gate  *		FAILURE = Map not updated
601*0Sstevel@tonic-gate  */
602*0Sstevel@tonic-gate suc_code
603*0Sstevel@tonic-gate update_map_from_dit(map_ctrl *map, bool_t log_flag) {
604*0Sstevel@tonic-gate 	__nis_table_mapping_t	*t;
605*0Sstevel@tonic-gate 	__nis_rule_value_t	*rv, *frv;
606*0Sstevel@tonic-gate 	__nis_ldap_search_t	*ls;
607*0Sstevel@tonic-gate 	__nis_object_dn_t	*objectDN = NULL;
608*0Sstevel@tonic-gate 	datum			*datval, *datkey;
609*0Sstevel@tonic-gate 	int			nr = 0, i, j, nv, numDNs;
610*0Sstevel@tonic-gate 	int			statP = SUCCESS, flag;
611*0Sstevel@tonic-gate 	char			*objname, **dn;
612*0Sstevel@tonic-gate 	/* Name of temporary entries DBM file */
613*0Sstevel@tonic-gate 	char			*temp_entries;
614*0Sstevel@tonic-gate 	/* Name of temporary TTL DBM file */
615*0Sstevel@tonic-gate 	char			*temp_ttl;
616*0Sstevel@tonic-gate 	/* Temporary DBM handles */
617*0Sstevel@tonic-gate 	DBM			*temp_entries_db;
618*0Sstevel@tonic-gate 	DBM			*temp_ttl_db;
619*0Sstevel@tonic-gate 	map_ctrl		temp_map;
620*0Sstevel@tonic-gate 	datum			key;
621*0Sstevel@tonic-gate 	char			*myself = "update_map_from_dit";
622*0Sstevel@tonic-gate 	bool_t			secure_flag;
623*0Sstevel@tonic-gate 	int			entry_count = 1;
624*0Sstevel@tonic-gate 	int			next_print = PRINT_FREQ;
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 	if (!map || !map->map_name || !map->domain) {
627*0Sstevel@tonic-gate 		return (FAILURE);
628*0Sstevel@tonic-gate 	}
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 	__nisdb_get_tsd()->escapeFlag = '\0';
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 	/*
633*0Sstevel@tonic-gate 	 * netgroup.byxxx maps are a special case. They are regenerated from
634*0Sstevel@tonic-gate 	 * the netgroup map, not the DIT, so handle special case.
635*0Sstevel@tonic-gate 	 */
636*0Sstevel@tonic-gate 	if ((0 == strcmp(map->map_name, NETGROUP_BYHOST)) ||
637*0Sstevel@tonic-gate 		0 == (strcmp(map->map_name,  NETGROUP_BYUSER))) {
638*0Sstevel@tonic-gate 		return (update_netgroup_byxxx(map));
639*0Sstevel@tonic-gate 	}
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 	/* Get the mapping information for the map */
642*0Sstevel@tonic-gate 	if ((t = mappingFromMap(map->map_name, map->domain, &statP)) == 0) {
643*0Sstevel@tonic-gate 		if (statP == MAP_NO_MAPPING_EXISTS)
644*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_WARNING,
645*0Sstevel@tonic-gate 			"%s: No mapping information available for %s,%s",
646*0Sstevel@tonic-gate 				myself, map->map_name, map->domain);
647*0Sstevel@tonic-gate 		return (FAILURE);
648*0Sstevel@tonic-gate 	}
649*0Sstevel@tonic-gate 
650*0Sstevel@tonic-gate 	/* Allocate and set up names */
651*0Sstevel@tonic-gate 	if (SUCCESS != alloc_temp_names(map->map_path,
652*0Sstevel@tonic-gate 				&temp_entries, &temp_ttl)) {
653*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
654*0Sstevel@tonic-gate 			"%s: Unable to create map names for %s",
655*0Sstevel@tonic-gate 			myself, map->map_path);
656*0Sstevel@tonic-gate 		return (FAILURE);
657*0Sstevel@tonic-gate 	}
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	/* Create temp entry and TTL file */
660*0Sstevel@tonic-gate 	if ((temp_entries_db = dbm_open(temp_entries, O_RDWR | O_CREAT, 0644))
661*0Sstevel@tonic-gate 						== NULL) {
662*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR, "%s: Could not open %s",
663*0Sstevel@tonic-gate 						myself, temp_entries);
664*0Sstevel@tonic-gate 		sfree(temp_entries);
665*0Sstevel@tonic-gate 		sfree(temp_ttl);
666*0Sstevel@tonic-gate 		return (FAILURE);
667*0Sstevel@tonic-gate 	}
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	if ((temp_ttl_db = dbm_open(temp_ttl, O_RDWR | O_CREAT, 0644))
670*0Sstevel@tonic-gate 						== NULL) {
671*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR, "%s: Could not open %s",
672*0Sstevel@tonic-gate 						myself, temp_ttl);
673*0Sstevel@tonic-gate 		dbm_close(temp_entries_db);
674*0Sstevel@tonic-gate 		delete_map(temp_entries);
675*0Sstevel@tonic-gate 		sfree(temp_entries);
676*0Sstevel@tonic-gate 		sfree(temp_ttl);
677*0Sstevel@tonic-gate 		return (FAILURE);
678*0Sstevel@tonic-gate 	}
679*0Sstevel@tonic-gate 
680*0Sstevel@tonic-gate 	/* Initialize domainContext tsd */
681*0Sstevel@tonic-gate 	__nisdb_get_tsd()->domainContext = 0;
682*0Sstevel@tonic-gate 	for (i = 0; i < ypDomains.numDomains; i++) {
683*0Sstevel@tonic-gate 		if (0 == ypDomains.domainLabels[i])
684*0Sstevel@tonic-gate 			continue;
685*0Sstevel@tonic-gate 		if (0 == strcasecmp(map->domain, ypDomains.domainLabels[i])) {
686*0Sstevel@tonic-gate 			__nisdb_get_tsd()->domainContext = ypDomains.domains[i];
687*0Sstevel@tonic-gate 			break;
688*0Sstevel@tonic-gate 		}
689*0Sstevel@tonic-gate 	}
690*0Sstevel@tonic-gate 
691*0Sstevel@tonic-gate 	if (!(objname = getFullMapName(map->map_name, map->domain))) {
692*0Sstevel@tonic-gate 		if (temp_entries_db)
693*0Sstevel@tonic-gate 			dbm_close(temp_entries_db);
694*0Sstevel@tonic-gate 		if (temp_ttl_db)
695*0Sstevel@tonic-gate 			dbm_close(temp_ttl_db);
696*0Sstevel@tonic-gate 		delete_map(temp_entries);
697*0Sstevel@tonic-gate 		sfree(temp_entries);
698*0Sstevel@tonic-gate 		delete_map(temp_ttl);
699*0Sstevel@tonic-gate 		sfree(temp_ttl);
700*0Sstevel@tonic-gate 		return (FAILURE);
701*0Sstevel@tonic-gate 	}
702*0Sstevel@tonic-gate 
703*0Sstevel@tonic-gate 	/* Try each mapping for the map */
704*0Sstevel@tonic-gate 	for (flag = 0; t != 0; t = t->next) {
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 		/* Check if the mapping is the correct one */
707*0Sstevel@tonic-gate 		if (strcmp(objname, t->objName) != 0) {
708*0Sstevel@tonic-gate 			continue;
709*0Sstevel@tonic-gate 		}
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 		/* Check if rulesFromLDAP are provided */
712*0Sstevel@tonic-gate 		if (t->numRulesFromLDAP == 0) {
713*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
714*0Sstevel@tonic-gate 				"%s: No rulesFromLDAP available for %s (%s)",
715*0Sstevel@tonic-gate 				myself, t->dbId, map->map_name);
716*0Sstevel@tonic-gate 			continue;
717*0Sstevel@tonic-gate 		}
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 		/* Set flag to indicate update is enabled */
720*0Sstevel@tonic-gate 		flag = 1;
721*0Sstevel@tonic-gate 		/* Create ldap request for enumeration */
722*0Sstevel@tonic-gate 		for (objectDN = t->objectDN;
723*0Sstevel@tonic-gate 				objectDN && objectDN->read.base;
724*0Sstevel@tonic-gate 				objectDN = objectDN->next) {
725*0Sstevel@tonic-gate 			if ((ls = createLdapRequest(t, 0, 0, 1, NULL,
726*0Sstevel@tonic-gate 						objectDN)) == 0) {
727*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
728*0Sstevel@tonic-gate 					"%s: Failed to create "
729*0Sstevel@tonic-gate 					"ldapSearch request for "
730*0Sstevel@tonic-gate 					"%s (%s) for base %s",
731*0Sstevel@tonic-gate 					myself, t->dbId,
732*0Sstevel@tonic-gate 					map->map_name,
733*0Sstevel@tonic-gate 					objectDN->read.base);
734*0Sstevel@tonic-gate 				statP = FAILURE;
735*0Sstevel@tonic-gate 				break;
736*0Sstevel@tonic-gate 			}
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 			if (log_flag) {
739*0Sstevel@tonic-gate 				printf("Waiting for LDAP search results.\n");
740*0Sstevel@tonic-gate 			}
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate 			/* Query LDAP */
743*0Sstevel@tonic-gate 			nr = (ls->isDN)?0:-1;
744*0Sstevel@tonic-gate 			rv = ldapSearch(ls, &nr, 0, &statP);
745*0Sstevel@tonic-gate 			freeLdapSearch(ls);
746*0Sstevel@tonic-gate 			if (rv == 0) {
747*0Sstevel@tonic-gate 				if (statP == LDAP_NO_SUCH_OBJECT) {
748*0Sstevel@tonic-gate 				/*
749*0Sstevel@tonic-gate 				 * No Entry exists in the ldap server. Not
750*0Sstevel@tonic-gate 				 * a problem. Maybe there are just no entries
751*0Sstevel@tonic-gate 				 * in this map.
752*0Sstevel@tonic-gate 				 */
753*0Sstevel@tonic-gate 					continue;
754*0Sstevel@tonic-gate 				}
755*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
756*0Sstevel@tonic-gate 					"%s: ldapSearch error %d "
757*0Sstevel@tonic-gate 					"(%s) for %s (%s) for base %s",
758*0Sstevel@tonic-gate 					myself, statP, ldap_err2string(statP),
759*0Sstevel@tonic-gate 					t->dbId, map->map_name,
760*0Sstevel@tonic-gate 					objectDN->read.base);
761*0Sstevel@tonic-gate 				statP = FAILURE;
762*0Sstevel@tonic-gate 				break;
763*0Sstevel@tonic-gate 			}
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 			if (log_flag) {
766*0Sstevel@tonic-gate 				printf("Processing search results.\n");
767*0Sstevel@tonic-gate 			}
768*0Sstevel@tonic-gate 
769*0Sstevel@tonic-gate 			/* Obtain list of DNs for logging */
770*0Sstevel@tonic-gate 			if ((dn = findDNs(myself, rv, nr, 0, &numDNs)) == 0) {
771*0Sstevel@tonic-gate 				statP = FAILURE;
772*0Sstevel@tonic-gate 				break;
773*0Sstevel@tonic-gate 			}
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 			/* For each entry in the result  do the following */
776*0Sstevel@tonic-gate 			for (i = 0; i < nr; i++) {
777*0Sstevel@tonic-gate 			/* Convert LDAP data to NIS equivalents */
778*0Sstevel@tonic-gate 				statP = buildNISRuleValue(t, &rv[i],
779*0Sstevel@tonic-gate 						map->domain);
780*0Sstevel@tonic-gate 				if (statP == MAP_INDEXLIST_ERROR)
781*0Sstevel@tonic-gate 					continue;
782*0Sstevel@tonic-gate 				if (statP != SUCCESS) {
783*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
784*0Sstevel@tonic-gate 					    "%s: Conversion error %d (LDAP to "
785*0Sstevel@tonic-gate 					    "name=value pairs) "
786*0Sstevel@tonic-gate 					    "for (dn: %s) for "
787*0Sstevel@tonic-gate 					    "%s (%s) for base %s",
788*0Sstevel@tonic-gate 					    myself, statP, NIL(dn[i]),
789*0Sstevel@tonic-gate 					    t->dbId, map->map_name,
790*0Sstevel@tonic-gate 					    objectDN->read.base);
791*0Sstevel@tonic-gate 					continue;
792*0Sstevel@tonic-gate 				}
793*0Sstevel@tonic-gate 
794*0Sstevel@tonic-gate 				/* Obtain the datum for value */
795*0Sstevel@tonic-gate 				datval = ruleValueToDatum(t, &rv[i], &statP);
796*0Sstevel@tonic-gate 				if (datval == 0) {
797*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
798*0Sstevel@tonic-gate 						"%s: Conversion error %d "
799*0Sstevel@tonic-gate 						"(name=value pairs to NIS)"
800*0Sstevel@tonic-gate 						" for (dn: %s) for "
801*0Sstevel@tonic-gate 						"%s (%s) for base %s",
802*0Sstevel@tonic-gate 						myself, statP, NIL(dn[i]),
803*0Sstevel@tonic-gate 						t->dbId, map->map_name,
804*0Sstevel@tonic-gate 						objectDN->read.base);
805*0Sstevel@tonic-gate 					continue;
806*0Sstevel@tonic-gate 				}
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate 				/* Obtain the datum for key */
809*0Sstevel@tonic-gate 				datkey = getKeyFromRuleValue(t, &rv[i],
810*0Sstevel@tonic-gate 						&nv, &statP);
811*0Sstevel@tonic-gate 				if (datkey == 0) {
812*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
813*0Sstevel@tonic-gate 						"%s: Unable to obtain NIS "
814*0Sstevel@tonic-gate 						"key from LDAP data (dn:%s) "
815*0Sstevel@tonic-gate 						"for %s (%s) for base %s",
816*0Sstevel@tonic-gate 						myself, NIL(dn[i]), t->dbId,
817*0Sstevel@tonic-gate 						map->map_name,
818*0Sstevel@tonic-gate 						objectDN->read.base);
819*0Sstevel@tonic-gate 					sfree(datval->dptr);
820*0Sstevel@tonic-gate 					sfree(datval);
821*0Sstevel@tonic-gate 					continue;
822*0Sstevel@tonic-gate 				}
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate 				/* Write to the temporary map */
825*0Sstevel@tonic-gate 				for (j = 0; j < nv; j++, entry_count ++) {
826*0Sstevel@tonic-gate 					if (datkey[j].dsize == 0)
827*0Sstevel@tonic-gate 						continue;
828*0Sstevel@tonic-gate 					errno = 0;
829*0Sstevel@tonic-gate 					/* DBM_INSERT to match */
830*0Sstevel@tonic-gate 					/* singleReadFromDIT */
831*0Sstevel@tonic-gate 					if (dbm_store(temp_entries_db,
832*0Sstevel@tonic-gate 						datkey[j],
833*0Sstevel@tonic-gate 						*datval,
834*0Sstevel@tonic-gate 						DBM_INSERT) < 0) {
835*0Sstevel@tonic-gate 						/*
836*0Sstevel@tonic-gate 						 * For some cases errno may
837*0Sstevel@tonic-gate 						 * still be 0 but dbm_error
838*0Sstevel@tonic-gate 						 * isn't informative at all.
839*0Sstevel@tonic-gate 						 */
840*0Sstevel@tonic-gate 						logmsg(MSG_NOTIMECHECK,
841*0Sstevel@tonic-gate 						    LOG_WARNING,
842*0Sstevel@tonic-gate 						    "%s: dbm store error "
843*0Sstevel@tonic-gate 						    "(errno=%d) "
844*0Sstevel@tonic-gate 						    "for (key=%s, value=%s) "
845*0Sstevel@tonic-gate 						    "for %s (%s) for base %s",
846*0Sstevel@tonic-gate 						    myself,
847*0Sstevel@tonic-gate 						    errno,
848*0Sstevel@tonic-gate 						    datkey[j].dptr,
849*0Sstevel@tonic-gate 						    datval->dptr, t->dbId,
850*0Sstevel@tonic-gate 						    map->map_name,
851*0Sstevel@tonic-gate 						    objectDN->read.base);
852*0Sstevel@tonic-gate 						/* clear the error */
853*0Sstevel@tonic-gate 						dbm_clearerr(temp_entries_db);
854*0Sstevel@tonic-gate 					}
855*0Sstevel@tonic-gate 					sfree(datkey[j].dptr);
856*0Sstevel@tonic-gate 
857*0Sstevel@tonic-gate 					if (log_flag && (entry_count >=
858*0Sstevel@tonic-gate 							next_print)) {
859*0Sstevel@tonic-gate 						printf("%d entries processed\n",
860*0Sstevel@tonic-gate 							entry_count);
861*0Sstevel@tonic-gate 						next_print *= 2;
862*0Sstevel@tonic-gate 					}
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate 				}
865*0Sstevel@tonic-gate 				sfree(datkey);
866*0Sstevel@tonic-gate 				sfree(datval->dptr);
867*0Sstevel@tonic-gate 				sfree(datval);
868*0Sstevel@tonic-gate 			}
869*0Sstevel@tonic-gate 
870*0Sstevel@tonic-gate 			freeRuleValue(rv, nr);
871*0Sstevel@tonic-gate 			freeDNs(dn, numDNs);
872*0Sstevel@tonic-gate 		} /* End of for over objectDN */
873*0Sstevel@tonic-gate 	}
874*0Sstevel@tonic-gate 	sfree(objname);
875*0Sstevel@tonic-gate 
876*0Sstevel@tonic-gate 	if (t != 0 || flag == 0) {
877*0Sstevel@tonic-gate 		if (temp_entries_db)
878*0Sstevel@tonic-gate 			dbm_close(temp_entries_db);
879*0Sstevel@tonic-gate 		if (temp_ttl_db)
880*0Sstevel@tonic-gate 			dbm_close(temp_ttl_db);
881*0Sstevel@tonic-gate 		delete_map(temp_entries);
882*0Sstevel@tonic-gate 		sfree(temp_entries);
883*0Sstevel@tonic-gate 		delete_map(temp_ttl);
884*0Sstevel@tonic-gate 		sfree(temp_ttl);
885*0Sstevel@tonic-gate 		return (statP);
886*0Sstevel@tonic-gate 	}
887*0Sstevel@tonic-gate 	/* Set up enough of map_ctrl to call update_entry_ttl */
888*0Sstevel@tonic-gate 	temp_map.map_name = map->map_name;
889*0Sstevel@tonic-gate 	temp_map.domain = map->domain;
890*0Sstevel@tonic-gate 	temp_map.ttl = temp_ttl_db;
891*0Sstevel@tonic-gate 
892*0Sstevel@tonic-gate 	/* Generate new TTL file */
893*0Sstevel@tonic-gate 	key = dbm_firstkey(temp_entries_db);
894*0Sstevel@tonic-gate 	while (key.dptr != 0) {
895*0Sstevel@tonic-gate 		if (!is_special_key(&key))
896*0Sstevel@tonic-gate 			/*
897*0Sstevel@tonic-gate 			 * We don't want all the entries to time out at the
898*0Sstevel@tonic-gate 			 * same time so create random TTLs.
899*0Sstevel@tonic-gate 			 */
900*0Sstevel@tonic-gate 			if (FAILURE == update_entry_ttl(&temp_map, &key,
901*0Sstevel@tonic-gate 								TTL_RAND))
902*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
903*0Sstevel@tonic-gate 					"%s: Could not update TTL for "
904*0Sstevel@tonic-gate 					"(key=%s) for map %s,%s",
905*0Sstevel@tonic-gate 					myself, NIL(key.dptr), map->map_name,
906*0Sstevel@tonic-gate 					map->domain);
907*0Sstevel@tonic-gate 		key = dbm_nextkey(temp_entries_db);
908*0Sstevel@tonic-gate 	}
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 	/* Update map TTL */
911*0Sstevel@tonic-gate 	if (SUCCESS != update_map_ttl(&temp_map)) {
912*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR, "%s: Could not update map TTL "
913*0Sstevel@tonic-gate 			"for %s,%s", myself, map->map_name, map->domain);
914*0Sstevel@tonic-gate 	}
915*0Sstevel@tonic-gate 
916*0Sstevel@tonic-gate 	/* Set up 'special' nis entries */
917*0Sstevel@tonic-gate 	add_special_entries(temp_entries_db, map, &secure_flag);
918*0Sstevel@tonic-gate 
919*0Sstevel@tonic-gate 	/* Close temp DBM files */
920*0Sstevel@tonic-gate 	dbm_close(temp_entries_db);
921*0Sstevel@tonic-gate 	dbm_close(temp_ttl_db);
922*0Sstevel@tonic-gate 
923*0Sstevel@tonic-gate 	/* Lock access to the map for copy */
924*0Sstevel@tonic-gate 	lock_map_ctrl(map);
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 	/* Move temp maps to real ones */
927*0Sstevel@tonic-gate 	rename_map(temp_entries, map->map_path, secure_flag);
928*0Sstevel@tonic-gate 	rename_map(temp_ttl, map->ttl_path, secure_flag);
929*0Sstevel@tonic-gate 
930*0Sstevel@tonic-gate 	/* Free file names */
931*0Sstevel@tonic-gate 	sfree(temp_entries);
932*0Sstevel@tonic-gate 	sfree(temp_ttl);
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 	/* Unlock map */
935*0Sstevel@tonic-gate 	unlock_map_ctrl(map);
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate 	return (SUCCESS);
938*0Sstevel@tonic-gate }
939*0Sstevel@tonic-gate 
940*0Sstevel@tonic-gate /*
941*0Sstevel@tonic-gate  * FUNCTION :	get_mapping_map_list()
942*0Sstevel@tonic-gate  *
943*0Sstevel@tonic-gate  * DESCRIPTION:	Gets a list of nis maps for a given domain specified in the
944*0Sstevel@tonic-gate  *		mapping file. This information is not saved so have to go
945*0Sstevel@tonic-gate  *		through the entire hash table. At least this is only done at
946*0Sstevel@tonic-gate  *		initialization time.
947*0Sstevel@tonic-gate  *
948*0Sstevel@tonic-gate  * GIVEN :	Domain name
949*0Sstevel@tonic-gate  *
950*0Sstevel@tonic-gate  * RETURNS :	List of map names in malloced memory. MUST BE FREED BY CALLER.
951*0Sstevel@tonic-gate  */
952*0Sstevel@tonic-gate char **
953*0Sstevel@tonic-gate get_mapping_map_list(char *domain)
954*0Sstevel@tonic-gate {
955*0Sstevel@tonic-gate 	char *myself = "get_mapping_map_list";
956*0Sstevel@tonic-gate 	__nis_hash_item_mt *it;
957*0Sstevel@tonic-gate 	int	i, j, size;
958*0Sstevel@tonic-gate 	char 	*end_ptr, *copy_ptr;
959*0Sstevel@tonic-gate 	char	**res;		/* Result array */
960*0Sstevel@tonic-gate 	char	**res_old;	/* Old value of res during realloc */
961*0Sstevel@tonic-gate 	int	array_size;	/* Current malloced size */
962*0Sstevel@tonic-gate 	int	res_count = 0;	/* Current result count */
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 	/*
965*0Sstevel@tonic-gate 	 * Always need an array even if just for terminator. Normally one
966*0Sstevel@tonic-gate 	 * chunk will be enough.
967*0Sstevel@tonic-gate 	 */
968*0Sstevel@tonic-gate 	res = am(myself, ARRAY_CHUNK * sizeof (char *));
969*0Sstevel@tonic-gate 	if (NULL == res)
970*0Sstevel@tonic-gate 		return (NULL);
971*0Sstevel@tonic-gate 	array_size = ARRAY_CHUNK;
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 	/* Work out hash table length */
974*0Sstevel@tonic-gate 	size = sizeof (ldapMappingList.keys) / sizeof (ldapMappingList.keys[0]);
975*0Sstevel@tonic-gate 	/* For all hash table entries */
976*0Sstevel@tonic-gate 	for (i = 0; i < size; i++) {
977*0Sstevel@tonic-gate 		/* Walk linked list for this hash table entry */
978*0Sstevel@tonic-gate 		for (it = ldapMappingList.keys[i]; NULL != it; it = it->next) {
979*0Sstevel@tonic-gate 
980*0Sstevel@tonic-gate 			/* Check it's not a split field entry */
981*0Sstevel@tonic-gate 			if (0 != ((__nis_table_mapping_t *)it)->numSplits)
982*0Sstevel@tonic-gate 				continue;
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 			/* Check right domain (minus trailing dot) */
985*0Sstevel@tonic-gate 			if (strlen(domain) >= strlen(it->name))
986*0Sstevel@tonic-gate 				continue;
987*0Sstevel@tonic-gate 			end_ptr = it->name + strlen(it->name) -
988*0Sstevel@tonic-gate 							strlen(domain) - 1;
989*0Sstevel@tonic-gate 			if (',' != *(end_ptr - 1))
990*0Sstevel@tonic-gate 				continue;
991*0Sstevel@tonic-gate 			if (0 != strncmp(end_ptr, domain, strlen(domain)))
992*0Sstevel@tonic-gate 				continue;
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate 			/* Check if we need to enlarge array */
995*0Sstevel@tonic-gate 			if ((res_count + 1) >= array_size) {
996*0Sstevel@tonic-gate 				array_size += ARRAY_CHUNK;
997*0Sstevel@tonic-gate 				res_old = res;
998*0Sstevel@tonic-gate 				res = realloc(res, array_size *
999*0Sstevel@tonic-gate 							sizeof (char *));
1000*0Sstevel@tonic-gate 				if (NULL == res) {
1001*0Sstevel@tonic-gate 					res_old[res_count] = NULL;
1002*0Sstevel@tonic-gate 					free_passwd_list(res_old);
1003*0Sstevel@tonic-gate 					return (NULL);
1004*0Sstevel@tonic-gate 				}
1005*0Sstevel@tonic-gate 			}
1006*0Sstevel@tonic-gate 
1007*0Sstevel@tonic-gate 			/*
1008*0Sstevel@tonic-gate 			 * We will need the sequence number when we come to
1009*0Sstevel@tonic-gate 			 * sort the entries so for now store a pointer to
1010*0Sstevel@tonic-gate 			 * the __nis_hash_item_mt.
1011*0Sstevel@tonic-gate 			 */
1012*0Sstevel@tonic-gate 			res[res_count] = (char *)it;
1013*0Sstevel@tonic-gate 			res_count ++;
1014*0Sstevel@tonic-gate 		}
1015*0Sstevel@tonic-gate 	}
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate 	/* Terminate array */
1018*0Sstevel@tonic-gate 	res[res_count] = NULL;
1019*0Sstevel@tonic-gate 
1020*0Sstevel@tonic-gate 	/* Bubble sort entries into the same order as mapping file */
1021*0Sstevel@tonic-gate 	for (i = res_count - 2; 0 <= i; i--) {
1022*0Sstevel@tonic-gate 		for (j = 0; j <= i; j++) {
1023*0Sstevel@tonic-gate 			if (((__nis_table_mapping_t *)res[j + 1])->seq_num <
1024*0Sstevel@tonic-gate 				((__nis_table_mapping_t *)res[j])->seq_num) {
1025*0Sstevel@tonic-gate 				end_ptr = res[j];
1026*0Sstevel@tonic-gate 				res[j] = res[j+1];
1027*0Sstevel@tonic-gate 				res[j + 1] = end_ptr;
1028*0Sstevel@tonic-gate 			}
1029*0Sstevel@tonic-gate 		}
1030*0Sstevel@tonic-gate 	}
1031*0Sstevel@tonic-gate 
1032*0Sstevel@tonic-gate 	/* Finally copy the real strings in to each entry */
1033*0Sstevel@tonic-gate 	for (i = 0; NULL != res[i]; i ++) {
1034*0Sstevel@tonic-gate 
1035*0Sstevel@tonic-gate 		/* Get hash table entry back */
1036*0Sstevel@tonic-gate 		it = (__nis_hash_item_mt *)res[i];
1037*0Sstevel@tonic-gate 
1038*0Sstevel@tonic-gate 		end_ptr = it->name + strlen(it->name) - strlen(domain) - 1;
1039*0Sstevel@tonic-gate 
1040*0Sstevel@tonic-gate 		/* What we really need is strndup() */
1041*0Sstevel@tonic-gate 		res[i] = am(myself, end_ptr - it->name + 1);
1042*0Sstevel@tonic-gate 		if (NULL == res[i]) {
1043*0Sstevel@tonic-gate 			free_map_list(res);
1044*0Sstevel@tonic-gate 			return (NULL);
1045*0Sstevel@tonic-gate 		}
1046*0Sstevel@tonic-gate 
1047*0Sstevel@tonic-gate 		/* Copy from start to end_ptr */
1048*0Sstevel@tonic-gate 		memcpy(res[i], it->name, end_ptr-it->name - 1);
1049*0Sstevel@tonic-gate 	}
1050*0Sstevel@tonic-gate 
1051*0Sstevel@tonic-gate 	return (res);
1052*0Sstevel@tonic-gate }
1053*0Sstevel@tonic-gate 
1054*0Sstevel@tonic-gate /*
1055*0Sstevel@tonic-gate  * FUNCTION :	make_nis_container()
1056*0Sstevel@tonic-gate  *
1057*0Sstevel@tonic-gate  * DESCRIPTION: Sets up container for map_name in the DIT.
1058*0Sstevel@tonic-gate  *
1059*0Sstevel@tonic-gate  * GIVEN :	Map name
1060*0Sstevel@tonic-gate  *		The domain name.
1061*0Sstevel@tonic-gate  *		Flag indicating if container should be created.
1062*0Sstevel@tonic-gate  *
1063*0Sstevel@tonic-gate  * RETURNS :	SUCCESS	= It worked
1064*0Sstevel@tonic-gate  *		FAILURE	= There was a problem.
1065*0Sstevel@tonic-gate  */
1066*0Sstevel@tonic-gate suc_code
1067*0Sstevel@tonic-gate make_nis_container(char *map_name, char *domain, bool_t init_containers) {
1068*0Sstevel@tonic-gate 	int			i, rc, statP = SUCCESS;
1069*0Sstevel@tonic-gate 	__nis_table_mapping_t	*t;
1070*0Sstevel@tonic-gate 	char			*dn;
1071*0Sstevel@tonic-gate 	char			*myself = "make_nis_container";
1072*0Sstevel@tonic-gate 
1073*0Sstevel@tonic-gate 	if (!map_name || !domain)
1074*0Sstevel@tonic-gate 		return (FAILURE);
1075*0Sstevel@tonic-gate 
1076*0Sstevel@tonic-gate 	if (FALSE == init_containers) {
1077*0Sstevel@tonic-gate 		/*
1078*0Sstevel@tonic-gate 		 * If we are not creating containers it is debatable what we
1079*0Sstevel@tonic-gate 		 * should do . Maybe we should check for a pre-
1080*0Sstevel@tonic-gate 		 * existing container and return failure if it does not exist.
1081*0Sstevel@tonic-gate 		 *
1082*0Sstevel@tonic-gate 		 * For now we assume the user will not have called us in this
1083*0Sstevel@tonic-gate 		 * mode unless they know what they are doing. So return
1084*0Sstevel@tonic-gate 		 * success. If they have got it wrong then latter writes will
1085*0Sstevel@tonic-gate 		 * fail.
1086*0Sstevel@tonic-gate 		 */
1087*0Sstevel@tonic-gate 		return (SUCCESS);
1088*0Sstevel@tonic-gate 	}
1089*0Sstevel@tonic-gate 
1090*0Sstevel@tonic-gate 	/* Get the mapping information for the map */
1091*0Sstevel@tonic-gate 	if ((t = mappingFromMap(map_name, domain, &statP)) == 0) {
1092*0Sstevel@tonic-gate 		if (statP == MAP_NO_MAPPING_EXISTS)
1093*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
1094*0Sstevel@tonic-gate 			"%s: No mapping information available for %s,%s",
1095*0Sstevel@tonic-gate 				myself, NIL(map_name), NIL(domain));
1096*0Sstevel@tonic-gate 		return (FAILURE);
1097*0Sstevel@tonic-gate 	}
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate 	/* Two times. One for readDN and other for writeDN */
1100*0Sstevel@tonic-gate 	for (i = 0; i < 2; i++) {
1101*0Sstevel@tonic-gate 		if (i == 0)
1102*0Sstevel@tonic-gate 			dn = t->objectDN->read.base;
1103*0Sstevel@tonic-gate 		else {
1104*0Sstevel@tonic-gate 			if (t->objectDN->write.base == 0) {
1105*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_INFO,
1106*0Sstevel@tonic-gate 					"%s: No baseDN in writespec. Write "
1107*0Sstevel@tonic-gate 					"disabled for %s,%s",
1108*0Sstevel@tonic-gate 					myself, map_name, domain);
1109*0Sstevel@tonic-gate 				break;
1110*0Sstevel@tonic-gate 			}
1111*0Sstevel@tonic-gate 			if (!strcasecmp(dn, t->objectDN->write.base))
1112*0Sstevel@tonic-gate 				break;
1113*0Sstevel@tonic-gate 			dn = t->objectDN->write.base;
1114*0Sstevel@tonic-gate 		}
1115*0Sstevel@tonic-gate 
1116*0Sstevel@tonic-gate 		if ((rc = makeNISObject(0, dn)) == FAILURE) {
1117*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
1118*0Sstevel@tonic-gate 				"%s: Unable to create ldap container (dn: %s) "
1119*0Sstevel@tonic-gate 				"for %s,%s", myself, dn, map_name, domain);
1120*0Sstevel@tonic-gate 			return (FAILURE);
1121*0Sstevel@tonic-gate 		}
1122*0Sstevel@tonic-gate 	}
1123*0Sstevel@tonic-gate 	return (SUCCESS);
1124*0Sstevel@tonic-gate }
1125*0Sstevel@tonic-gate 
1126*0Sstevel@tonic-gate /*
1127*0Sstevel@tonic-gate  * FUNCTION :	make_nis_domain()
1128*0Sstevel@tonic-gate  *
1129*0Sstevel@tonic-gate  * DESCRIPTION:	Sets up a nisDomainObject in the DIT
1130*0Sstevel@tonic-gate  *
1131*0Sstevel@tonic-gate  * GIVEN:	Name of the domain
1132*0Sstevel@tonic-gate  *		Flag indicating if domain should be create or possibly just
1133*0Sstevel@tonic-gate  *		checked for.
1134*0Sstevel@tonic-gate  */
1135*0Sstevel@tonic-gate suc_code
1136*0Sstevel@tonic-gate make_nis_domain(char *domain, bool_t init_containers) {
1137*0Sstevel@tonic-gate 
1138*0Sstevel@tonic-gate 	if (FALSE == init_containers) {
1139*0Sstevel@tonic-gate 		/*
1140*0Sstevel@tonic-gate 		 * If we are not creating containers it is debatable what we
1141*0Sstevel@tonic-gate 		 * should do with domains. Maybe we should check for a pre-
1142*0Sstevel@tonic-gate 		 * existing domain and return failure if it does not exist.
1143*0Sstevel@tonic-gate 		 *
1144*0Sstevel@tonic-gate 		 * For now we assume the user will not have called us in this
1145*0Sstevel@tonic-gate 		 * mode unless they know what they are doing. So return
1146*0Sstevel@tonic-gate 		 * success. If they have got it wrong then latter writes will
1147*0Sstevel@tonic-gate 		 * fail.
1148*0Sstevel@tonic-gate 		 */
1149*0Sstevel@tonic-gate 		return (SUCCESS);
1150*0Sstevel@tonic-gate 	}
1151*0Sstevel@tonic-gate 
1152*0Sstevel@tonic-gate 	/* Create the domain */
1153*0Sstevel@tonic-gate 	return (makeNISObject(domain, 0));
1154*0Sstevel@tonic-gate }
1155*0Sstevel@tonic-gate 
1156*0Sstevel@tonic-gate /*
1157*0Sstevel@tonic-gate  * FUNCTION:	update_netgroup_byxxx()
1158*0Sstevel@tonic-gate  *
1159*0Sstevel@tonic-gate  * DESCRIPTION:	Updates the netgroup.byxxx series of maps based on the current
1160*0Sstevel@tonic-gate  *		netgroup file. We invoke revnetgroup so that if any changes
1161*0Sstevel@tonic-gate  *		are made to this utility the same changes are made here.
1162*0Sstevel@tonic-gate  *
1163*0Sstevel@tonic-gate  * INPUTS:	map_ctrl containing lots of information about the map and a
1164*0Sstevel@tonic-gate  *		pointer to it's lock which will be required.
1165*0Sstevel@tonic-gate  *
1166*0Sstevel@tonic-gate  * OUTPUTS:	SUCCESS = Map updated
1167*0Sstevel@tonic-gate  *		FAILURE = Map not updated
1168*0Sstevel@tonic-gate  */
1169*0Sstevel@tonic-gate suc_code
1170*0Sstevel@tonic-gate update_netgroup_byxxx(map_ctrl *map) {
1171*0Sstevel@tonic-gate 	/* Name of temporary entries DBM file */
1172*0Sstevel@tonic-gate 	char			*temp_entries;
1173*0Sstevel@tonic-gate 	/* Name of temporary TTL DBM file */
1174*0Sstevel@tonic-gate 	char			*temp_ttl;
1175*0Sstevel@tonic-gate 	/* Temporary DBM handles */
1176*0Sstevel@tonic-gate 	DBM			*temp_entries_db;
1177*0Sstevel@tonic-gate 	DBM			*temp_ttl_db;
1178*0Sstevel@tonic-gate 	map_ctrl		temp_map;
1179*0Sstevel@tonic-gate 	char			*myself = "update_netgroup_byxxx";
1180*0Sstevel@tonic-gate 	char			*cmdbuf;
1181*0Sstevel@tonic-gate 	int			cmd_length;
1182*0Sstevel@tonic-gate 	datum			key;
1183*0Sstevel@tonic-gate 	map_ctrl		*netgroupmap;
1184*0Sstevel@tonic-gate 	int			res;
1185*0Sstevel@tonic-gate 	/* Temporary revnetgroup files */
1186*0Sstevel@tonic-gate 	const char 		*byhost = NETGROUP_BYHOST "_REV" TEMP_POSTFIX;
1187*0Sstevel@tonic-gate 	const char 		*byuser = NETGROUP_BYUSER "_REV" TEMP_POSTFIX;
1188*0Sstevel@tonic-gate 	const char		*temp_file_name;
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate 
1191*0Sstevel@tonic-gate 	/*
1192*0Sstevel@tonic-gate 	 * We need to use two different temporary files: one for netgroup.byhost
1193*0Sstevel@tonic-gate 	 * and other for netgroup.byuser, since these two maps can be updated
1194*0Sstevel@tonic-gate 	 * simultaneously. These temporary files will hold the output of
1195*0Sstevel@tonic-gate 	 * revnetgroup [-h|-u] command. They are then used to generate the
1196*0Sstevel@tonic-gate 	 * corresponding dbm files and thereafter deleted.
1197*0Sstevel@tonic-gate 	 */
1198*0Sstevel@tonic-gate 	if (0 == strcmp(map->map_name, NETGROUP_BYHOST))
1199*0Sstevel@tonic-gate 		temp_file_name = byhost;
1200*0Sstevel@tonic-gate 	else
1201*0Sstevel@tonic-gate 		temp_file_name = byuser;
1202*0Sstevel@tonic-gate 
1203*0Sstevel@tonic-gate 	/* Alloc enough cmd buf for revnet cmd */
1204*0Sstevel@tonic-gate 	cmd_length = strlen("/usr/sbin/makedbm -u ") +
1205*0Sstevel@tonic-gate 			(strlen(map->map_path) - strlen(map->map_name)) +
1206*0Sstevel@tonic-gate 			strlen(NETGROUP_MAP) +
1207*0Sstevel@tonic-gate 			strlen(" | /usr/sbin/revnetgroup -h > ") +
1208*0Sstevel@tonic-gate 			(strlen(map->map_path) - strlen(map->map_name)) +
1209*0Sstevel@tonic-gate 			strlen(temp_file_name) + 1;
1210*0Sstevel@tonic-gate 	cmdbuf = am(myself, cmd_length);
1211*0Sstevel@tonic-gate 
1212*0Sstevel@tonic-gate 	if (NULL == cmdbuf) {
1213*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
1214*0Sstevel@tonic-gate 				"%s: Could not alloc cmdbuf.", myself);
1215*0Sstevel@tonic-gate 		return (FAILURE);
1216*0Sstevel@tonic-gate 	}
1217*0Sstevel@tonic-gate 
1218*0Sstevel@tonic-gate 	/*
1219*0Sstevel@tonic-gate 	 * If necessary update (and wait for) netgroups map. This is a lot of
1220*0Sstevel@tonic-gate 	 * work but if the netgroup map itself is not being accessed it may
1221*0Sstevel@tonic-gate 	 * contain information that is not up to date with the DIT.
1222*0Sstevel@tonic-gate 	 *
1223*0Sstevel@tonic-gate 	 * We use the cmdbuf to store the qualified netgroup map name there will
1224*0Sstevel@tonic-gate 	 * be enough space for this but we are not yet creating the cmd.
1225*0Sstevel@tonic-gate 	 */
1226*0Sstevel@tonic-gate 	strlcpy(cmdbuf, map->map_path, strlen(map->map_path) -
1227*0Sstevel@tonic-gate 						strlen(map->map_name) + 1);
1228*0Sstevel@tonic-gate 	strcat(cmdbuf, NETGROUP_MAP);
1229*0Sstevel@tonic-gate 	netgroupmap = (map_ctrl *)shim_dbm_open(cmdbuf,
1230*0Sstevel@tonic-gate 						O_RDWR | O_CREAT, 0644);
1231*0Sstevel@tonic-gate 	if (NULL == netgroupmap) {
1232*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
1233*0Sstevel@tonic-gate 				"%s: Could not update %s.", myself, cmdbuf);
1234*0Sstevel@tonic-gate 		sfree(cmdbuf);
1235*0Sstevel@tonic-gate 		return (FAILURE);
1236*0Sstevel@tonic-gate 	}
1237*0Sstevel@tonic-gate 
1238*0Sstevel@tonic-gate 	if (has_map_expired(netgroupmap)) {
1239*0Sstevel@tonic-gate 		lock_map_ctrl(netgroupmap);
1240*0Sstevel@tonic-gate 		update_map_if_required(netgroupmap, TRUE);
1241*0Sstevel@tonic-gate 		unlock_map_ctrl(netgroupmap);
1242*0Sstevel@tonic-gate 	}
1243*0Sstevel@tonic-gate 	shim_dbm_close((DBM *)netgroupmap);
1244*0Sstevel@tonic-gate 
1245*0Sstevel@tonic-gate 	/* Dump netgroup file through revnetgroup to a temp file */
1246*0Sstevel@tonic-gate 	strcpy(cmdbuf, "/usr/sbin/makedbm -u ");
1247*0Sstevel@tonic-gate 
1248*0Sstevel@tonic-gate 	/* Unmake the netgroup file in same domain as map */
1249*0Sstevel@tonic-gate 	strncat(cmdbuf, map->map_path, strlen(map->map_path) -
1250*0Sstevel@tonic-gate 						strlen(map->map_name));
1251*0Sstevel@tonic-gate 	strcat(cmdbuf, NETGROUP_MAP);
1252*0Sstevel@tonic-gate 
1253*0Sstevel@tonic-gate 	if (0 == strcmp(map->map_name, NETGROUP_BYHOST)) {
1254*0Sstevel@tonic-gate 		strcat(cmdbuf, " | /usr/sbin/revnetgroup -h > ");
1255*0Sstevel@tonic-gate 	} else {
1256*0Sstevel@tonic-gate 		strcat(cmdbuf, " | /usr/sbin/revnetgroup -u > ");
1257*0Sstevel@tonic-gate 	}
1258*0Sstevel@tonic-gate 
1259*0Sstevel@tonic-gate 	/* Create temp file file in same domain as map */
1260*0Sstevel@tonic-gate 	strncat(cmdbuf, map->map_path, strlen(map->map_path) -
1261*0Sstevel@tonic-gate 						strlen(map->map_name));
1262*0Sstevel@tonic-gate 	strcat(cmdbuf, temp_file_name);
1263*0Sstevel@tonic-gate 
1264*0Sstevel@tonic-gate 	if (0 > system(cmdbuf)) {
1265*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR, "%s: Could not run \"%s\" "
1266*0Sstevel@tonic-gate 			"(errno=%d)", myself, cmdbuf, errno);
1267*0Sstevel@tonic-gate 		sfree(cmdbuf);
1268*0Sstevel@tonic-gate 		return (FAILURE);
1269*0Sstevel@tonic-gate 	}
1270*0Sstevel@tonic-gate 	sfree(cmdbuf);
1271*0Sstevel@tonic-gate 
1272*0Sstevel@tonic-gate 	/* Allocate and set up names */
1273*0Sstevel@tonic-gate 	if (SUCCESS != alloc_temp_names(map->map_path,
1274*0Sstevel@tonic-gate 				&temp_entries, &temp_ttl)) {
1275*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
1276*0Sstevel@tonic-gate 			"%s: Unable to create map names for %s",
1277*0Sstevel@tonic-gate 			myself, map->map_path);
1278*0Sstevel@tonic-gate 		return (FAILURE);
1279*0Sstevel@tonic-gate 	}
1280*0Sstevel@tonic-gate 
1281*0Sstevel@tonic-gate 	/* Make the temporary DBM file */
1282*0Sstevel@tonic-gate 	cmdbuf = am(myself, strlen("/usr/sbin/makedbm") +
1283*0Sstevel@tonic-gate 			(strlen(map->map_path) - strlen(map->map_name)) +
1284*0Sstevel@tonic-gate 			strlen(temp_file_name) +
1285*0Sstevel@tonic-gate 			strlen(temp_entries) + 3);
1286*0Sstevel@tonic-gate 	if (NULL == cmdbuf) {
1287*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
1288*0Sstevel@tonic-gate 				"%s: Could not allocate cmdbuf.", myself);
1289*0Sstevel@tonic-gate 		sfree(temp_entries);
1290*0Sstevel@tonic-gate 		sfree(temp_ttl);
1291*0Sstevel@tonic-gate 		return (FAILURE);
1292*0Sstevel@tonic-gate 	}
1293*0Sstevel@tonic-gate 
1294*0Sstevel@tonic-gate 	strcpy(cmdbuf, "/usr/sbin/makedbm ");
1295*0Sstevel@tonic-gate 	strncat(cmdbuf, map->map_path, strlen(map->map_path) -
1296*0Sstevel@tonic-gate 						strlen(map->map_name));
1297*0Sstevel@tonic-gate 	strcat(cmdbuf, temp_file_name);
1298*0Sstevel@tonic-gate 	strcat(cmdbuf, " ");
1299*0Sstevel@tonic-gate 	strcat(cmdbuf, temp_entries);
1300*0Sstevel@tonic-gate 
1301*0Sstevel@tonic-gate 	if (0 > system(cmdbuf)) {
1302*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR, "%s: Could not run \"%s\" "
1303*0Sstevel@tonic-gate 			"(errno=%d)", myself, cmdbuf, errno);
1304*0Sstevel@tonic-gate 		sfree(cmdbuf);
1305*0Sstevel@tonic-gate 		sfree(temp_entries);
1306*0Sstevel@tonic-gate 		sfree(temp_ttl);
1307*0Sstevel@tonic-gate 		return (FAILURE);
1308*0Sstevel@tonic-gate 	}
1309*0Sstevel@tonic-gate 
1310*0Sstevel@tonic-gate 	/* Already have enough command buffer to rm temporary file */
1311*0Sstevel@tonic-gate 	strlcpy(cmdbuf, map->map_path, strlen(map->map_path) -
1312*0Sstevel@tonic-gate 						strlen(map->map_name) + 1);
1313*0Sstevel@tonic-gate 	strcat(cmdbuf, temp_file_name);
1314*0Sstevel@tonic-gate 	res = unlink(cmdbuf);
1315*0Sstevel@tonic-gate 	/* If the temp file did not exist no problem. Probably had no entries */
1316*0Sstevel@tonic-gate 	if ((0 != res) && (ENOENT != errno)) {
1317*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR, "%s: Could not delete \"%s\" "
1318*0Sstevel@tonic-gate 			"(errno=%d)", myself, cmdbuf, errno);
1319*0Sstevel@tonic-gate 		sfree(temp_entries);
1320*0Sstevel@tonic-gate 		sfree(temp_ttl);
1321*0Sstevel@tonic-gate 		sfree(cmdbuf);
1322*0Sstevel@tonic-gate 		return (FAILURE);
1323*0Sstevel@tonic-gate 	}
1324*0Sstevel@tonic-gate 	sfree(cmdbuf);
1325*0Sstevel@tonic-gate 
1326*0Sstevel@tonic-gate 	if ((temp_entries_db = dbm_open(temp_entries, O_RDWR | O_CREAT, 0644))
1327*0Sstevel@tonic-gate 						== NULL) {
1328*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR, "%s: Could not open %s",
1329*0Sstevel@tonic-gate 						myself, temp_entries);
1330*0Sstevel@tonic-gate 		sfree(temp_entries);
1331*0Sstevel@tonic-gate 		sfree(temp_ttl);
1332*0Sstevel@tonic-gate 		return (FAILURE);
1333*0Sstevel@tonic-gate 	}
1334*0Sstevel@tonic-gate 
1335*0Sstevel@tonic-gate 	if ((temp_ttl_db = dbm_open(temp_ttl, O_RDWR | O_CREAT, 0644))
1336*0Sstevel@tonic-gate 						== NULL) {
1337*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR, "%s: Could not open %s",
1338*0Sstevel@tonic-gate 						myself, temp_ttl);
1339*0Sstevel@tonic-gate 		dbm_close(temp_entries_db);
1340*0Sstevel@tonic-gate 		sfree(temp_entries);
1341*0Sstevel@tonic-gate 		sfree(temp_ttl);
1342*0Sstevel@tonic-gate 		return (FAILURE);
1343*0Sstevel@tonic-gate 	}
1344*0Sstevel@tonic-gate 
1345*0Sstevel@tonic-gate 	/*
1346*0Sstevel@tonic-gate 	 * Set up enough of map_ctrl to call update_entry_ttl. Since there is
1347*0Sstevel@tonic-gate 	 * no mapping, and thus not TTL, defined for these maps use the TTL
1348*0Sstevel@tonic-gate 	 * values for netgroup map
1349*0Sstevel@tonic-gate 	 */
1350*0Sstevel@tonic-gate 	temp_map.map_name = NETGROUP_MAP;
1351*0Sstevel@tonic-gate 	temp_map.domain = map->domain;
1352*0Sstevel@tonic-gate 	temp_map.ttl = temp_ttl_db;
1353*0Sstevel@tonic-gate 
1354*0Sstevel@tonic-gate 	/*
1355*0Sstevel@tonic-gate 	 * Generate new TTL file.  Since these maps work only on the whole map
1356*0Sstevel@tonic-gate 	 * expiry these will not actually be used but there presence makes it
1357*0Sstevel@tonic-gate 	 * easier to handle these maps in the same way as other maps.
1358*0Sstevel@tonic-gate 	 */
1359*0Sstevel@tonic-gate 	key = dbm_firstkey(temp_entries_db);
1360*0Sstevel@tonic-gate 	while (key.dptr != 0) {
1361*0Sstevel@tonic-gate 		if (!is_special_key(&key))
1362*0Sstevel@tonic-gate 			/*
1363*0Sstevel@tonic-gate 			 * For these maps want all timouts to be maximum
1364*0Sstevel@tonic-gate 			 */
1365*0Sstevel@tonic-gate 			if (FAILURE == update_entry_ttl(&temp_map, &key,
1366*0Sstevel@tonic-gate 								TTL_MAX))
1367*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
1368*0Sstevel@tonic-gate 					"%s: Could not update TTL for "
1369*0Sstevel@tonic-gate 					"(key=%s) for map %s,%s",
1370*0Sstevel@tonic-gate 					myself, NIL(key.dptr), map->map_name,
1371*0Sstevel@tonic-gate 					map->domain);
1372*0Sstevel@tonic-gate 		key = dbm_nextkey(temp_entries_db);
1373*0Sstevel@tonic-gate 	}
1374*0Sstevel@tonic-gate 
1375*0Sstevel@tonic-gate 	/* Update map TTL */
1376*0Sstevel@tonic-gate 	update_map_ttl(&temp_map);
1377*0Sstevel@tonic-gate 
1378*0Sstevel@tonic-gate 	/* Close temp DBM files */
1379*0Sstevel@tonic-gate 	dbm_close(temp_entries_db);
1380*0Sstevel@tonic-gate 	dbm_close(temp_ttl_db);
1381*0Sstevel@tonic-gate 
1382*0Sstevel@tonic-gate 	/* Lock access to the map for copy */
1383*0Sstevel@tonic-gate 	lock_map_ctrl(map);
1384*0Sstevel@tonic-gate 
1385*0Sstevel@tonic-gate 	/* Move temp maps to real ones */
1386*0Sstevel@tonic-gate 	rename_map(temp_entries, map->map_path, FALSE);
1387*0Sstevel@tonic-gate 	rename_map(temp_ttl, map->ttl_path, FALSE);
1388*0Sstevel@tonic-gate 
1389*0Sstevel@tonic-gate 	/* Free file names */
1390*0Sstevel@tonic-gate 	sfree(temp_entries);
1391*0Sstevel@tonic-gate 	sfree(temp_ttl);
1392*0Sstevel@tonic-gate 
1393*0Sstevel@tonic-gate 	/* Unlock map */
1394*0Sstevel@tonic-gate 	unlock_map_ctrl(map);
1395*0Sstevel@tonic-gate 
1396*0Sstevel@tonic-gate 	return (SUCCESS);
1397*0Sstevel@tonic-gate }
1398