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 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 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 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 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 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 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