1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * DESCRIPTION: Contains functions relating to movement of entire maps.
31  */
32 
33 #include <unistd.h>
34 #include <syslog.h>
35 #include <ndbm.h>
36 #include <string.h>
37 #include "ypsym.h"
38 #include "ypdefs.h"
39 #include "shim.h"
40 #include "yptol.h"
41 #include "../ldap_util.h"
42 
43 /*
44  * Switch on parts of ypdefs.h
45  */
46 USE_YPDBPATH
47 USE_DBM
48 
49 /*
50  * Decs
51  */
52 void add_separator(char *);
53 suc_code dump_domain_to_dit(char *, bool_t);
54 suc_code dump_map_to_dit(char *, char *, bool_t);
55 suc_code dump_maps_to_dit(bool_t);
56 suc_code dump_dit_to_map();
57 suc_code dump_dit_to_maps();
58 
59 /*
60  * FUNCTION :	dump_maps_to_dit()
61  *
62  * DESCRIPTION:	Dump all the OLD STYLE NIS maps into the DIT.
63  *
64  *		Since the DIT is not yet set up details about which maps and
65  *		domains exist are gathered from the N2L config file and the
66  *		existing map files.
67  *
68  * GIVEN :	Flag indicating if containers and domains should be set up.
69  *
70  * RETURNS :	Success code
71  */
72 suc_code
73 dump_maps_to_dit(bool_t init_containers)
74 {
75 	char **dom_list;
76 	int num_doms, i;
77 
78 	num_doms = get_mapping_domain_list(&dom_list);
79 
80 	/* Dump all domains in list */
81 	for (i = 0; i < num_doms; i++) {
82 		if (FAILURE == dump_domain_to_dit(dom_list[i], init_containers))
83 			return (FAILURE);
84 	}
85 
86 	return (SUCCESS);
87 }
88 
89 /*
90  * FUNCTION :	dump_domain_to_dit()
91  *
92  * DESCRIPTION:	Dumps all maps in one domain into the DIT
93  *
94  * GIVEN :	Name of the domain
95  *		Flag indicating if containers and domains should be set up.
96  *
97  * RETURNS :	SUCCESS = domain completely dumped
98  *		FAILURE = domain not completely dumped
99  *
100  */
101 suc_code
102 dump_domain_to_dit(char *dom_name, bool_t init_containers)
103 {
104 	char **map_list;
105 	int	i;
106 
107 	/* Set up nis domain object */
108 	if (SUCCESS != make_nis_domain(dom_name, init_containers)) {
109 		if (init_containers)
110 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
111 			"Could not make nisDomain object for %s", dom_name);
112 		else
113 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
114 			"Problem detected with nisDomain object for %s",
115 								dom_name);
116 		return (FAILURE);
117 	}
118 
119 	/* Get list of maps from mapping file */
120 	map_list = get_mapping_map_list(dom_name);
121 	if (NULL == map_list) {
122 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
123 			"Could not get map list for %s", dom_name);
124 		return (FAILURE);
125 	}
126 
127 	for (i = 0; NULL != map_list[i]; i++) {
128 		dump_map_to_dit(map_list[i], dom_name, init_containers);
129 	}
130 
131 	free_map_list(map_list);
132 
133 	return (SUCCESS);
134 }
135 
136 /*
137  * FUNCTION :	dump_map_to_dit()
138  *
139  * DESCRIPTION:	Dump a OLD STYLE NIS map into the DIT.
140  *
141  * GIVEN :	Name of map (not fully qualified)
142  *		Name of domain
143  *		Flag indicating if containers should be set up.
144  *
145  * RETURNS :	SUCCESS = Map copy completed
146  *		FAILURE = Map copy not completed
147  */
148 suc_code
149 dump_map_to_dit(char *map_name, char *domain, bool_t init_containers)
150 {
151 	char *myself = "dump_map_to_dit";
152 	DBM *dbm;
153 	datum key;
154 	datum value;
155 	char *map_path;		/* Qualified map name */
156 	int entry_count;
157 	int next_print;
158 
159 	printf("Copying map \"%s\", domain \"%s\", to LDAP.\n",
160 							map_name, domain);
161 
162 	/* Create the NIS container */
163 	if (SUCCESS != make_nis_container(map_name, domain, init_containers)) {
164 		if (init_containers)
165 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
166 				"Could not make container for %s %s",
167 				map_name, domain);
168 		else
169 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
170 				"Problem detected with container for %s %s",
171 				map_name, domain);
172 
173 		return (FAILURE);
174 	}
175 
176 	/* Make up fully qualified map name */
177 	map_path = (char *)am(myself, strlen(domain) + strlen(map_name) +
178 						ypdbpath_sz + 3);
179 	if (NULL == map_path) {
180 		logmsg(MSG_NOMEM, LOG_ERR,
181 			"Could not alloc memory for %s %s", map_name, domain);
182 		return (FAILURE);
183 	}
184 	strcpy(map_path, ypdbpath);
185 	add_separator(map_path);
186 	strcat(map_path, domain);
187 	add_separator(map_path);
188 	strcat(map_path, map_name);
189 
190 	/* Open the DBM file. Use real dbm call */
191 	dbm = dbm_open(map_path, O_RDONLY, 0644);
192 
193 	/* Finished with full name */
194 	sfree(map_path);
195 
196 	if (NULL == dbm) {
197 		/*
198 		 * This map probably didn't exist. No problem, user may be
199 		 * going to populate container using LDAP.
200 		 */
201 		return (SUCCESS);
202 	}
203 
204 	/*
205 	 * N2L has no lock for old style maps. No problem ypserv -i is the
206 	 * only thing that accesses them.
207 	 */
208 
209 	/* For all entries in file */
210 	for (key = dbm_firstkey(dbm), next_print = PRINT_FREQ, entry_count = 1;
211 		NULL != key.dptr; key = dbm_nextkey(dbm), entry_count ++) {
212 
213 		/* Don't write zero length keys */
214 		if (0 == key.dsize) {
215 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
216 			"Zero length key ignored in %s %s", map_name, domain);
217 			continue;
218 		}
219 
220 		/* Don't write 'special' nis entries */
221 		if (is_special_key(&key))
222 			continue;
223 
224 		/* Get entry */
225 		value = dbm_fetch(dbm, key);
226 
227 		/* Copy entry to DIT */
228 		if (SUCCESS != write_to_dit(map_name, domain, key, value,
229 								TRUE, TRUE))
230 			/* Syslog will have already been done */
231 			break;
232 
233 		/* If necessary print a progress report */
234 		if (entry_count >= next_print) {
235 			printf("%d entries processed.\n", entry_count);
236 			next_print *= 2;
237 		}
238 	}
239 
240 	dbm_close(dbm);
241 
242 	return (SUCCESS);
243 }
244 
245 /*
246  * FUNCTION :	dump_dit_to_maps()
247  *
248  * DESCRIPTION:	Dumps the contents of the DIT into the NEW STYLE NIS maps. If
249  *		the maps, or their TTL files do not exist creates them.
250  *
251  *		Since we are now treating the DIT as authoritative details of
252  *		which domains and maps exist are gathered from the DIT.
253  *
254  * GIVEN :	Nothing
255  *
256  * RETURNS :	Success code
257  */
258 suc_code
259 dump_dit_to_maps()
260 {
261 	char **dom_list;
262 	int dom_count;
263 	char *dom_path;
264 	char **map_list;
265 	int i, j;
266 	char *myself = "dump_dit_to_maps";
267 
268 	/* For all domain objects in DIT */
269 	dom_count = get_mapping_domain_list(&dom_list);
270 
271 	if (0 == dom_count) {
272 		/* No problem, maybe no domains */
273 		return (SUCCESS);
274 	}
275 
276 	/* Dump all domains in list */
277 	for (i = 0; i < dom_count; i++) {
278 
279 		/* If necessary create domain directory */
280 		dom_path = (char *)am(myself, ypdbpath_sz +
281 						strlen(dom_list[i]) + 2);
282 		if (NULL == dom_path) {
283 			return (FAILURE);
284 		}
285 
286 		strcpy(dom_path, ypdbpath);
287 		strcat(dom_path, "/");
288 		strcat(dom_path, dom_list[i]);
289 
290 		if (0 != mkdir(dom_path, 0644)) {
291 			/* If dir exists fine. Just use it */
292 			if (EEXIST != errno) {
293 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
294 				"Could not make create domain directory %s",
295 								dom_path);
296 				sfree(dom_path);
297 			}
298 		}
299 
300 		sfree(dom_path);
301 
302 		/* Get list of maps for this domain */
303 		map_list = get_mapping_map_list(dom_list[i]);
304 		if (NULL == map_list) {
305 			/* No problem. Just no maps in this domain */
306 			continue;
307 		}
308 
309 		/* For all maps in domain */
310 		for (j = 0; map_list[j] != NULL; j++) {
311 			/* A normal map update will initialize it. */
312 			if (FAILURE == dump_dit_to_map(map_list[j],
313 							dom_list[i])) {
314 				free_map_list(map_list);
315 				return (FAILURE);
316 			}
317 
318 			/* If we have a netgroup also generate netgroup.byxxx */
319 			if (0 == strcmp(map_list[j], NETGROUP_MAP)) {
320 				if (FAILURE == dump_dit_to_map(NETGROUP_BYHOST,
321 								dom_list[i])) {
322 					free_map_list(map_list);
323 					return (FAILURE);
324 				}
325 				if (FAILURE == dump_dit_to_map(NETGROUP_BYUSER,
326 								dom_list[i])) {
327 					free_map_list(map_list);
328 					return (FAILURE);
329 				}
330 			}
331 		}
332 		free_map_list(map_list);
333 	}
334 	return (SUCCESS);
335 }
336 
337 /*
338  * FUNCTION :	dump_dit_to_map()
339  *
340  * DESCRIPTION:	Dumps the contents of the DIT into one NEW STYLE NIS map. If
341  *		the map, or its TTL file does not exist creates them.
342  *
343  *		This is the same operation as is carried out when updating a
344  *		map that has timed out. As a result we can call the normal
345  *		update function.
346  *
347  *
348  * GIVEN :	Map name (unqualified)
349  *		Domain name.
350  *
351  * RETURNS :	SUCCESS = Map copy complete
352  *		FAILURE = Problems
353  */
354 suc_code
355 dump_dit_to_map(char *map_name, char *domain)
356 {
357 	char *myself = "dump_dit_to_map";
358 	map_ctrl map;
359 	char 	*map_path;
360 
361 	printf("Copying LDAP data to map \"%s\", domain \"%s\".\n",
362 							map_name, domain);
363 
364 	/*
365 	 * To call update_map_from_dit() we need an initialized map_ctrl.
366 	 * The easiest way to get this is to generate a full path to the new
367 	 * map and then call map_ctrl_init().
368 	 */
369 	map_path = (char *)am(myself, ypdbpath_sz + strlen(map_name) +
370 				strlen(domain) + strlen(NTOL_PREFIX) + 3);
371 	if (NULL == map_path)
372 		return (FAILURE);
373 
374 	strcpy(map_path, ypdbpath);
375 	add_separator(map_path);
376 	strcat(map_path, domain);
377 	add_separator(map_path);
378 	strcat(map_path, NTOL_PREFIX);
379 	strcat(map_path, map_name);
380 
381 	if (FAILURE == map_ctrl_init(&map, map_path)) {
382 		sfree(map_path);
383 		return (FAILURE);
384 	}
385 
386 	sfree(map_path);
387 
388 	/*
389 	 * This is called before anything else is running so don't need to
390 	 * do normal update lock.
391 	 */
392 	return (update_map_from_dit(&map, TRUE));
393 }
394 
395 /*
396  * FUNCTION :	add_seperator()
397  *
398  * DESCRIPTION:	Adds a file separator to a string (which must already be big
399  *		enough.)
400  *
401  * GIVEN :	Pointer to the string
402  *
403  * RETURNS :	Nothing
404  */
405 void
406 add_separator(char *str)
407 {
408 	char *p;
409 
410 	p = str + strlen(str);
411 	*p = SEP_CHAR;
412 	*(p+1) = '\0';
413 }
414