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