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