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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * DESCRIPTION: Contains functions relating to the creation and manipulation 31 * of map_ctrl structures. These are used to hold information 32 * specific to one NIS map. 33 * 34 * Because each of these contains a significant amount of state 35 * information about an individual map they are created (on the 36 * heap) when a map is opened and destroyed when it is closed. 37 * The overhead of doing this is less than maintaining a pool 38 * of map_ctrls. 39 * 40 * If two processes access the same map two map_ctrls will be 41 * created with similar contents (but differing DBM pointers). 42 * Both will have the same hash value so when one is locked 43 * access to the other will also be prevented. 44 */ 45 46 #include <unistd.h> 47 #include <syslog.h> 48 #include <ndbm.h> 49 #include <string.h> 50 #include "ypsym.h" 51 #include "ypdefs.h" 52 #include "shim.h" 53 #include "yptol.h" 54 #include "../ldap_util.h" 55 56 /* Switch on parts of ypdefs.h */ 57 USE_DBM 58 59 /* 60 * FUNCTION: create_map_ctrl(); 61 * 62 * DESCRIPTION: Create and a new map_ctrl in a non opened state. 63 * 64 * INPUTS: Fully qualified map name 65 * 66 * OUTPUTS: Pointer to map_ctrl 67 * NULL on failure. 68 * 69 */ 70 map_ctrl * 71 create_map_ctrl(char *name) 72 { 73 char *myself = "create_map_ctrl"; 74 map_ctrl *map; 75 76 map = (map_ctrl *)am(myself, sizeof (map_ctrl)); 77 if (NULL == map) { 78 logmsg(MSG_NOTIMECHECK, LOG_ERR, "Could not alloc map_ctrl"); 79 return (NULL); 80 } 81 82 /* Clear new map (in case we have to free it) */ 83 map->entries = NULL; 84 map->hash_val = 0; 85 map->map_name = NULL; 86 map->domain = NULL; 87 map->map_path = NULL; 88 map->ttl = NULL; 89 map->ttl_path = NULL; 90 map->trad_map_path = NULL; 91 map->key_data.dptr = NULL; 92 map->open_mode = 0; 93 map->open_flags = 0; 94 95 /* 96 * Initialize the fields of the map_ctrl. By doing this once here we 97 * can save a lot of work as map entries are accessed. 98 */ 99 if (SUCCESS != map_ctrl_init(map, name)) { 100 logmsg(MSG_NOTIMECHECK, LOG_ERR, 101 "Could not initialize map_ctrl for %s", name); 102 free_map_ctrl(map); 103 return (NULL); 104 } 105 106 return (map); 107 } 108 109 /* 110 * FUNCTION : map_ctrl_init() 111 * 112 * DESCRIPTION: Initializes the fields of a map_ctrl structure. 113 * 114 * By doing this once (when the map_ctrl is created) we avoid 115 * numerous other function having to repeat this string 116 * manipulation. 117 * 118 * GIVEN : Pointer to the structure 119 * Fully qualified name of the map 120 * 121 * RETURNS : SUCCESS = map_ctrl fully set up. 122 * FAILURE = map_ctrl not set up CALLER MUST FREE. 123 */ 124 suc_code 125 map_ctrl_init(map_ctrl *map, char *name) 126 { 127 char *myself = "map_ctrl_init"; 128 char *p, *q; 129 130 /* Save map path for future reference */ 131 map->map_path = (char *)strdup(name); 132 if (NULL == map->map_path) { 133 logmsg(MSG_NOMEM, LOG_ERR, 134 "Could not duplicate map path %s", map); 135 return (FAILURE); 136 } 137 138 /* Work out map's unqualified name from path */ 139 p = strrchr(name, SEP_CHAR); 140 if (NULL == p) { 141 /* Must be at least a domain and name */ 142 logmsg(MSG_NOTIMECHECK, LOG_ERR, 143 "Could not find separator in map path %s", map); 144 return (FAILURE); 145 } 146 q = p + 1; 147 148 /* Check for and remove N2L prefix */ 149 if (yptol_mode) { 150 /* 151 * Check for and remove N2L prefix. If not found not a problem 152 * we open some old style maps during DIT initialization. 153 */ 154 if (0 == strncmp(q, NTOL_PREFIX, strlen(NTOL_PREFIX))) 155 q += strlen(NTOL_PREFIX); 156 } else { 157 if (0 == strncmp(q, NTOL_PREFIX, strlen(NTOL_PREFIX))) 158 logmsg(MSG_NOTIMECHECK, LOG_ERR, 159 "Working in non N2L mode and path %s " 160 "contains N2L prefix", name); 161 } 162 163 /* Save unqualified map name */ 164 map->map_name = strdup(q); 165 if (NULL == map->map_name) { 166 logmsg(MSG_NOMEM, LOG_ERR, 167 "Could not duplicate map name %s", q); 168 return (FAILURE); 169 } 170 171 /* Work out map's domain name from path */ 172 for (q = p-1; (SEP_CHAR != *q) && (q > name); q--); 173 174 if (q <= name) { 175 /* Didn't find separator */ 176 logmsg(MSG_NOTIMECHECK, LOG_ERR, 177 "Could not find domain in map path %s", name); 178 return (FAILURE); 179 } 180 181 map->domain = (char *)am(myself, p - q); 182 if (NULL == map->domain) { 183 logmsg(MSG_NOMEM, LOG_ERR, 184 "Could not alloc memory for domain in path %s", name); 185 return (FAILURE); 186 } 187 strncpy(map->domain, q + 1, p-q-1); 188 map->domain[p-q-1] = '\0'; 189 190 /* Work out extra names required by N2L */ 191 if (yptol_mode) { 192 /* 193 * Work out what old style NIS path would have been. This is 194 * used to check for date of DBM file so add the DBM 195 * extension. 196 */ 197 map->trad_map_path = (char *)am(myself, strlen(map->map_name) + 198 + strlen(dbm_pag) + (p - name) + 2); 199 if (NULL == map->trad_map_path) { 200 logmsg(MSG_NOMEM, LOG_ERR, 201 "Could not alocate memory for " 202 "traditional map path derived from %s", name); 203 return (FAILURE); 204 } 205 206 strncpy(map->trad_map_path, name, p - name + 1); 207 map->trad_map_path[p - name + 1] = '\0'; 208 strcat(map->trad_map_path, map->map_name); 209 strcat(map->trad_map_path, dbm_pag); 210 211 /* Generate qualified TTL file name */ 212 map->ttl_path = (char *)am(myself, strlen(map->map_path) + 213 strlen(TTL_POSTFIX) + 1); 214 if (NULL == map->ttl_path) { 215 logmsg(MSG_NOMEM, LOG_ERR, 216 "Could not alocate memory for " 217 "ttl path derived from %s", name); 218 return (FAILURE); 219 } 220 221 strcpy(map->ttl_path, map->map_path); 222 strcat(map->ttl_path, TTL_POSTFIX); 223 } 224 225 /* Work out hash value */ 226 map->hash_val = hash(name); 227 228 /* Set up magic number */ 229 map->magic = MAP_MAGIC; 230 231 /* Null out pointers */ 232 map->entries = NULL; 233 map->ttl = NULL; 234 235 /* No key data yet */ 236 map->key_data.dptr = NULL; 237 map->key_data.dsize = 0; 238 239 return (SUCCESS); 240 } 241 242 /* 243 * FUNCTION: get_map_crtl(); 244 * 245 * DESCRIPTION: Find an existing map_ctrl for a map of a given DBM * (i.e. 246 * handle) . If none exists return an error. 247 * 248 * INPUTS: Map handle 249 * 250 * OUTPUTS: Pointer to map_ctrl 251 * NULL on failure. 252 * 253 */ 254 map_ctrl * 255 get_map_ctrl(DBM *db) 256 { 257 /* Check that this really is a map_ctrl not a DBM */ 258 if (((map_ctrl *)db)->magic != MAP_MAGIC) { 259 logmsg(MSG_NOTIMECHECK, LOG_ERR, 260 "SHIM called with DBM ptr not map_crtl ptr"); 261 return (NULL); 262 } 263 264 /* Since this is an opaque pointer just cast it */ 265 return ((map_ctrl *)db); 266 } 267 268 /* 269 * FUNCTION: dup_map_ctrl() 270 * 271 * DESCRIPTION: Duplicates a map_ctrl structure 272 * 273 * GIVEN : Map_ctrl to duplicate 274 * 275 * RETURNS : Pointer to a new malloced map_ctrl. CALLER MUST FREE 276 * NULL on failure. 277 */ 278 map_ctrl * 279 dup_map_ctrl(map_ctrl *old_map) 280 { 281 map_ctrl *new_map; 282 283 /* 284 * Could save a little bit of time by duplicating the static parts 285 * of the old map but on balance it is cleaner to just make a new one 286 * from scratch 287 */ 288 new_map = create_map_ctrl(old_map->map_path); 289 290 if (NULL == new_map) 291 return (NULL); 292 293 /* If old map had open handles duplicate them */ 294 if (NULL != old_map->entries) { 295 new_map->open_flags = old_map->open_flags; 296 new_map->open_mode = old_map->open_mode; 297 if (FAILURE == open_yptol_files(new_map)) { 298 free_map_ctrl(new_map); 299 return (NULL); 300 } 301 } 302 303 return (new_map); 304 } 305 306 /* 307 * FUNCTION: free_map_crtl(); 308 * 309 * DESCRIPTION: Free contents of a map_ctr structure and closed any open 310 * DBM files. 311 * 312 * INPUTS: Pointer to pointer to a map_ctrl. 313 * 314 * OUTPUTS: Nothing 315 * 316 */ 317 void 318 free_map_ctrl(map_ctrl *map) 319 { 320 321 if (NULL != map->entries) { 322 dbm_close(map->entries); 323 map->entries = NULL; 324 } 325 326 if (NULL != map->map_name) { 327 sfree(map->map_name); 328 map->map_name = NULL; 329 } 330 331 if (NULL != map->map_path) { 332 sfree(map->map_path); 333 map->map_path = NULL; 334 } 335 336 if (NULL != map->domain) { 337 sfree(map->domain); 338 map->domain = NULL; 339 } 340 341 if (yptol_mode) { 342 if (NULL != map->ttl) { 343 dbm_close(map->ttl); 344 map->ttl = NULL; 345 } 346 347 if (NULL != map->trad_map_path) { 348 sfree(map->trad_map_path); 349 map->trad_map_path = NULL; 350 } 351 352 if (NULL != map->ttl_path) { 353 sfree(map->ttl_path); 354 map->ttl_path = NULL; 355 } 356 357 if (NULL != map->key_data.dptr) { 358 sfree(map->key_data.dptr); 359 map->key_data.dptr = NULL; 360 map->key_data.dsize = 0; 361 } 362 } 363 364 map->magic = 0; 365 366 /* Since map_ctrls are now always in malloced memory */ 367 sfree(map); 368 369 } 370 371 /* 372 * FUNCTION : get_map_name() 373 * 374 * DESCRIPTION: Get the name of a map from its map_ctrl. This could be done 375 * as a simple dereference but this function hides the internal 376 * implementation of map_ctrl from higher layers. 377 * 378 * GIVEN : A map_ctrl pointer 379 * 380 * RETURNS : A pointer to the map_ctrl. Higher levels treat this as an 381 * opaque DBM pointer. 382 * NULL on failure. 383 */ 384 char * 385 get_map_name(DBM *db) 386 { 387 map_ctrl *map = (map_ctrl *)db; 388 389 if (NULL == map) 390 return (NULL); 391 392 return (map->map_name); 393 } 394 395 /* 396 * FUNCTION : set_key_data() 397 * 398 * DESCRIPTION: Sets up the key data freeing any that already exists. 399 * 400 * GIVEN : Pointer to the map_ctrl to set up. 401 * Datum containing the key. The dptr of this will be set to 402 * point to the key data. 403 * 404 * RETURNS : Nothing 405 */ 406 void 407 set_key_data(map_ctrl *map, datum *data) 408 { 409 char *myself = "set_key_data"; 410 411 /* 412 * Free up any existing key data. Because each dbm file can only have 413 * one enumeration going at a time this is safe. 414 */ 415 if (NULL != map->key_data.dptr) { 416 sfree(map->key_data.dptr); 417 map->key_data.dptr = NULL; 418 map->key_data.dsize = 0; 419 } 420 421 /* If nothing in key just return */ 422 if (NULL == data->dptr) 423 return; 424 425 /* Something is in the key so must duplicate out of static memory */ 426 map->key_data.dptr = (char *)am(myself, data->dsize); 427 if (NULL == map->key_data.dptr) { 428 logmsg(MSG_NOMEM, LOG_ERR, "Cannot alloc memory for key data"); 429 } else { 430 memcpy(map->key_data.dptr, data->dptr, data->dsize); 431 map->key_data.dsize = data->dsize; 432 } 433 434 /* Set datum to point to malloced version of the data */ 435 data->dptr = map->key_data.dptr; 436 437 return; 438 439 } 440 441 /* 442 * FUNCTION : open_yptol_files() 443 * 444 * DESCRIPTION: Opens both yptol files for a map. This is called both when a 445 * map is opened and when it is reopened as a result of an update 446 * operation. Must be called with map locked. 447 * 448 * GIVEN : Initialized map_ctrl 449 * 450 * RETURNS : SUCCESS = Maps opened 451 * FAILURE = Maps not opened (and mess tidied up) 452 */ 453 suc_code 454 open_yptol_files(map_ctrl *map) 455 { 456 457 /* Open entries map */ 458 map->entries = dbm_open(map->map_path, map->open_flags, map->open_mode); 459 460 if (NULL == map->entries) { 461 /* Maybe we were asked to open a non-existent map. No problem */ 462 return (FAILURE); 463 } 464 465 if (yptol_mode) { 466 /* Open TTLs map. Must always be writable */ 467 map->ttl = dbm_open(map->ttl_path, O_RDWR | O_CREAT, 0644); 468 if (NULL == map->ttl) { 469 logmsg(MSG_NOTIMECHECK, LOG_ERR, 470 "Cannot open TTL file %s", map->ttl_path); 471 dbm_close(map->entries); 472 map->entries = NULL; 473 return (FAILURE); 474 } 475 } 476 477 return (SUCCESS); 478 } 479