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