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