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 2008 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
ypmkfilename(domain,map,path)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
on_maplist(char * mapname,char ** list)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
add_in_maplist(char * mapname,char *** list,int * list_len)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
ypcheck_domain_yptol(char * domain)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
ypcheck_map_existence_yptol(char * pname)220 ypcheck_map_existence_yptol(char *pname)
221 {
222 char dbfile[MAXNAMLEN + sizeof (TTL_POSTFIX) + 1];
223 struct stat64 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 (stat64(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 (stat64(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 (stat64(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 (stat64(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
add_map_domain_to_list(char * domain,char *** map_list)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