xref: /illumos-gate/usr/src/lib/libnisdb/yptol/shim_ancil.c (revision f808c858fa61e7769218966759510a8b1190dfcf)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved  	*/
28 
29 /*
30  * Portions of this source code were derived from Berkeley 4.3 BSD
31  * under license from the Regents of the University of California.
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 #ifndef	lint
37 static	char sccsid[] = "%Z%%M% %I%     %E% SMI";
38 #endif
39 
40 #include <stdlib.h>
41 #include <dirent.h>
42 #include <strings.h>
43 #include "ypsym.h"
44 #include "ypdefs.h"
45 USE_YPDBPATH
46 USE_DBM
47 #include "shim.h"
48 #include "../ldap_util.h"
49 
50 /*
51  * This constructs a file name from a passed domain name, a passed map name,
52  * and a globally known YP data base path prefix.
53  *
54  * Has to be in shim because it needs the N2L prefix
55  *
56  * RETURNS :	TRUE = A name was successfully created
57  *		FALSE = A name could not be created
58  */
59 
60 bool_t
61 ypmkfilename(domain, map, path)
62 	char *domain;
63 	char *map;
64 	char *path;
65 {
66 	int length;
67 
68 	/* Do not allow any path as a domain name. */
69 	if (strchr(domain, '/') != NULL)
70 		return (FALSE);
71 
72 	length = strlen(domain) + strlen(map) + ypdbpath_sz + 3;
73 	if (yptol_mode)
74 		length += strlen(NTOL_PREFIX) + 1;
75 
76 	if ((MAXNAMLEN + 1) < length) {
77 		(void) fprintf(stderr, "ypserv:  Map name string too long.\n");
78 		return (FALSE);
79 	}
80 
81 	strcpy(path, ypdbpath);
82 	strcat(path, "/");
83 	strcat(path, domain);
84 	strcat(path, "/");
85 
86 	/* If in N2L mode add N2L prefix */
87 	if (yptol_mode)
88 		strcat(path, NTOL_PREFIX);
89 	strcat(path, map);
90 
91 	return (TRUE);
92 }
93 
94 /*
95  * check whether a map is already in an array/list
96  *
97  * RETURNS: TRUE if yes
98  *          FALSE if not
99  */
100 bool_t
101 on_maplist(char *mapname, char **list) {
102 	int i = 0;
103 
104 	if (list == NULL) {
105 		return (FALSE);
106 	}
107 
108 	while (list[i] != NULL) {
109 		if (strcmp(mapname, list[i++]) == 0) {
110 			return (TRUE);
111 		}
112 	}
113 
114 	return (FALSE);
115 }
116 
117 /*
118  * add a map at the end of an array/list
119  *
120  * list_len: if -1, we do not know list length
121  *
122  * RETURNS: TRUE if map was added
123  *          FALSE if not
124  */
125 bool_t
126 add_in_maplist(char *mapname, char ***list, int *list_len) {
127 	int i = 0;
128 	char **list_tmp;
129 
130 	if (list == NULL) {
131 		return (FALSE);
132 	}
133 
134 	list_tmp = *list;
135 
136 	if (list_tmp == NULL) {
137 		*list_len = 0;
138 	} else {
139 		/* find 1st free element */
140 		while (list_tmp[i] != NULL) {
141 			/*
142 			 * increment in loop so that
143 			 * list_tmp[i] == NULL
144 			 * when exiting
145 			 */
146 			i++;
147 		}
148 	}
149 
150 	/* if we don't know list length, assume we reach its end */
151 	if (*list_len == -1) {
152 		*list_len = i;
153 	}
154 
155 	/* do we need to reallocate ? */
156 	if (i+1 >= *list_len) {
157 		list_tmp = (char **)realloc(list_tmp,
158 				    (*list_len + ARRAY_CHUNK) *
159 					sizeof (char *));
160 		if (list_tmp == NULL) {
161 			return (FALSE);
162 		}
163 		*list = list_tmp;
164 		*list_len += ARRAY_CHUNK;
165 	}
166 
167 	/* add in list */
168 	(*list)[i] = strdup(mapname);
169 	if ((*list)[i] == NULL) {
170 		/* strdup() failed */
171 		return (FALSE);
172 	}
173 	(*list)[++i] = NULL;
174 
175 	return (TRUE);
176 }
177 
178 /*
179  * This checks to see whether a domain name is present at the local node as a
180  * subdirectory of ypdbpath
181  *
182  * Was originally in cmd/ypcmd/shared/ancil.c as ypcheck_domain(domain).
183  * Now ypcheck_domain(domain) calls this function.
184  */
185 bool
186 ypcheck_domain_yptol(char *domain)
187 {
188 	char path[MAXNAMLEN + 1];
189 	struct stat filestat;
190 	bool present = FALSE;
191 
192 	strcpy(path, ypdbpath);
193 	strcat(path, "/");
194 	if (strlcat(path, domain, MAXNAMLEN + 1) >=  MAXNAMLEN + 1)
195 		return (present);
196 
197 	if (stat(path, &filestat) != -1) {
198 		if (S_ISDIR(filestat.st_mode))
199 			present = TRUE;
200 	}
201 	return (present);
202 }
203 
204 /*
205  * This performs an existence check on the dbm data base files <name>.pag and
206  * <name>.dir.  pname is a ptr to the filename.  This should be an absolute
207  * path.
208  * Returns TRUE if the map exists and is accessible; else FALSE.
209  *
210  * Note:  The file name should be a "base" form, without a file "extension" of
211  * .dir or .pag appended.  See ypmkfilename for a function which will generate
212  * the name correctly.  Errors in the stat call will be reported at this level,
213  * however, the non-existence of a file is not considered an error, and so will
214  * not be reported.
215  *
216  * Was originally in cmd/ypcmd/shared/utils.c as ypcheck_map_existence().
217  * Now ypcheck_map_existence() calls this function.
218  */
219 bool
220 ypcheck_map_existence_yptol(char *pname)
221 {
222 	char dbfile[MAXNAMLEN + sizeof (TTL_POSTFIX) + 1];
223 	struct stat filestat;
224 	int len;
225 
226 	if (!pname || ((len = (int)strlen(pname)) == 0) ||
227 	    (len + sizeof (dbm_pag) + sizeof (TTL_POSTFIX)) >
228 	    sizeof (dbfile)) {
229 		return (FALSE);
230 	}
231 
232 	errno = 0;
233 
234 	/* Check for existance of .dir file */
235 	(void) strcpy(dbfile, pname);
236 	(void) strcat(dbfile, dbm_dir);
237 
238 	if (stat(dbfile, &filestat) == -1) {
239 		if (errno != ENOENT) {
240 			(void) fprintf(stderr,
241 				"ypserv:  Stat error on map file %s.\n",
242 				dbfile);
243 		}
244 		return (FALSE);
245 	}
246 
247 	/* Check for existance of .pag file */
248 	(void) strcpy(dbfile, pname);
249 	(void) strcat(dbfile, dbm_pag);
250 
251 	if (stat(dbfile, &filestat) == -1) {
252 		if (errno != ENOENT) {
253 			(void) fprintf(stderr,
254 				"ypserv:  Stat error on map file %s.\n",
255 				dbfile);
256 		}
257 		return (FALSE);
258 	}
259 
260 	if (yptol_mode) {
261 		/* Check for existance of TTL .dir file */
262 		(void) strcpy(dbfile, pname);
263 		(void) strcat(dbfile, TTL_POSTFIX);
264 		(void) strcat(dbfile, dbm_dir);
265 
266 		if (stat(dbfile, &filestat) == -1) {
267 			if (errno != ENOENT) {
268 				(void) fprintf(stderr,
269 					"ypserv:  Stat error on map file %s.\n",
270 					dbfile);
271 			}
272 			return (FALSE);
273 		}
274 
275 		/* Check for existance of TTL .pag file */
276 		(void) strcpy(dbfile, pname);
277 		(void) strcat(dbfile, TTL_POSTFIX);
278 		(void) strcat(dbfile, dbm_pag);
279 
280 		if (stat(dbfile, &filestat) == -1) {
281 			if (errno != ENOENT) {
282 				(void) fprintf(stderr,
283 					"ypserv:  Stat error on map file %s.\n",
284 					dbfile);
285 			}
286 			return (FALSE);
287 		}
288 	}
289 
290 	return (TRUE);
291 }
292 
293 /*
294  * This adds maps in a domain to a given list,
295  * from maps in /var/yp/<domain>
296  * Inspired from yplist_maps() in cmd/ypcmd/ypserv_ancil.c
297  *
298  * domain is the relevant domain name
299  * map_list is the list of maps in an array of map names,
300  *    which may or may not be empty
301  *
302  * RETURNS :    TRUE = everything went fine
303  *              FALSE = an error occured
304  */
305 bool_t
306 add_map_domain_to_list(char *domain, char ***map_list)
307 {
308 	char domdir[MAXNAMLEN + 1];
309 	char path[MAXNAMLEN + 1];
310 	int domdir_len = sizeof (domdir);
311 	DIR *dirp;
312 	struct dirent *dp;
313 	int name_len;
314 	int dbm_pag_len = sizeof (dbm_pag);
315 	char *ext;
316 	char *mapname;
317 	int map_list_len = -1;
318 
319 	if (map_list == NULL) {
320 		return (FALSE);
321 	}
322 
323 	/* no domain, not a problem */
324 	if (domain == NULL) {
325 		return (TRUE);
326 	}
327 
328 	/* not a valid domain, not a problem */
329 	if (!ypcheck_domain_yptol(domain)) {
330 		return (TRUE);
331 	}
332 
333 	if (snprintf(domdir, domdir_len, "%s/%s", ypdbpath, domain)
334 	    > domdir_len) {
335 		return (FALSE);
336 	}
337 
338 	if ((dirp = opendir(domdir)) == NULL) {
339 		return (FALSE);
340 	}
341 
342 	for (dp = readdir(dirp); dp != NULL;
343 	    dp = readdir(dirp)) {
344 		/*
345 		 * If it's possible that the file name is one of the two files
346 		 * implementing a map, remove the extension (dbm_pag or dbm_dir)
347 		 */
348 		name_len = (int)strlen(dp->d_name);
349 
350 		if (name_len < dbm_pag_len - 1) {
351 			continue;		/* Too Short */
352 		}
353 
354 		ext = &(dp->d_name[name_len - (dbm_pag_len - 1)]);
355 
356 		if (strcmp(ext, dbm_pag) != 0) {
357 			continue;		/* No dbm file extension */
358 		}
359 
360 		*ext = '\0';
361 
362 		/*
363 		 * In yptol mode look at LDAP_ prefixed maps. In non yptol mode
364 		 * ignore them.
365 		 */
366 		if (yptol_mode) {
367 			if (0 != strncmp(dp->d_name, NTOL_PREFIX,
368 			    strlen(NTOL_PREFIX))) {
369 				continue;
370 			}
371 
372 			/*
373 			 * Already have an LDAP_ prefix. Don't want to add it
374 			 * twice.
375 			 */
376 			mapname = dp->d_name + strlen(NTOL_PREFIX);
377 		} else {
378 			if (0 == strncmp(dp->d_name, NTOL_PREFIX,
379 			    strlen(NTOL_PREFIX))) {
380 				continue;
381 			}
382 			mapname = dp->d_name;
383 		}
384 
385 		if (ypmkfilename(domain, mapname, path) == FALSE) {
386 			(void) closedir(dirp);
387 			return (FALSE);
388 		}
389 
390 		/*
391 		 * At this point, path holds the map file base name (no dbm
392 		 * file extension), and mapname holds the map name.
393 		 */
394 		if (ypcheck_map_existence_yptol(path) &&
395 		    !on_maplist(mapname, *map_list)) {
396 			if (add_in_maplist(mapname, map_list, &map_list_len) ==
397 			    FALSE) {
398 				(void) closedir(dirp);
399 				return (FALSE);
400 			}
401 		}
402 	}
403 
404 	(void) closedir(dirp);
405 	return (TRUE);
406 }
407