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.
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.
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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * DESCRIPTION: Contains functions relating to the creation and manipulation
30 * of map_ctrl structures. These are used to hold information
31 * specific to one NIS map.
33 * Because each of these contains a significant amount of state
34 * information about an individual map they are created (on the
35 * heap) when a map is opened and destroyed when it is closed.
36 * The overhead of doing this is less than maintaining a pool
39 * If two processes access the same map two map_ctrls will be
40 * created with similar contents (but differing DBM pointers).
41 * Both will have the same hash value so when one is locked
42 * access to the other will also be prevented.
50 #include <sys/param.h>
55 #include "../ldap_util.h"
57 extern int hash(char *s
);
58 extern bool_t
add_map_domain_to_list(char *domain
, char ***map_list
);
61 * Static variables for locking mechanism in
63 * map_id_list: hash table for map lists
64 * max_map: max number of maps in map_id_list
65 * it is also used as the map ID for
66 * unknown maps, see get_map_id()
67 * in usr/src/cmd/ypcmd/shared/lockmap.c
69 static map_id_elt_t
*map_id_list
[MAXHASH
];
70 static int max_map
= 0;
72 /* Switch on parts of ypdefs.h */
77 * FUNCTION: create_map_ctrl();
79 * DESCRIPTION: Create and a new map_ctrl in a non opened state.
81 * INPUTS: Fully qualified map name
83 * OUTPUTS: Pointer to map_ctrl
88 create_map_ctrl(char *name
)
90 char *myself
= "create_map_ctrl";
93 map
= (map_ctrl
*)am(myself
, sizeof (map_ctrl
));
95 logmsg(MSG_NOTIMECHECK
, LOG_ERR
, "Could not alloc map_ctrl");
99 /* Clear new map (in case we have to free it) */
102 map
->map_name
= NULL
;
104 map
->map_path
= NULL
;
106 map
->ttl_path
= NULL
;
107 map
->trad_map_path
= NULL
;
108 map
->key_data
.dptr
= NULL
;
113 * Initialize the fields of the map_ctrl. By doing this once here we
114 * can save a lot of work as map entries are accessed.
116 if (SUCCESS
!= map_ctrl_init(map
, name
)) {
117 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
118 "Could not initialize map_ctrl for %s", name
);
127 * FUNCTION : map_ctrl_init()
129 * DESCRIPTION: Initializes the fields of a map_ctrl structure.
131 * By doing this once (when the map_ctrl is created) we avoid
132 * numerous other function having to repeat this string
135 * GIVEN : Pointer to the structure
136 * Fully qualified name of the map
138 * RETURNS : SUCCESS = map_ctrl fully set up.
139 * FAILURE = map_ctrl not set up CALLER MUST FREE.
142 map_ctrl_init(map_ctrl
*map
, char *name
)
144 char *myself
= "map_ctrl_init";
147 /* Save map path for future reference */
148 map
->map_path
= (char *)strdup(name
);
149 if (NULL
== map
->map_path
) {
150 logmsg(MSG_NOMEM
, LOG_ERR
,
151 "Could not duplicate map path %s", map
);
155 /* Work out map's unqualified name from path */
156 p
= strrchr(name
, SEP_CHAR
);
158 /* Must be at least a domain and name */
159 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
160 "Could not find separator in map path %s", map
);
165 /* Check for and remove N2L prefix */
168 * Check for and remove N2L prefix. If not found not a problem
169 * we open some old style maps during DIT initialization.
171 if (0 == strncmp(q
, NTOL_PREFIX
, strlen(NTOL_PREFIX
)))
172 q
+= strlen(NTOL_PREFIX
);
174 if (0 == strncmp(q
, NTOL_PREFIX
, strlen(NTOL_PREFIX
)))
175 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
176 "Working in non N2L mode and path %s "
177 "contains N2L prefix", name
);
180 /* Save unqualified map name */
181 map
->map_name
= strdup(q
);
182 if (NULL
== map
->map_name
) {
183 logmsg(MSG_NOMEM
, LOG_ERR
,
184 "Could not duplicate map name %s", q
);
188 /* Work out map's domain name from path */
189 for (q
= p
-1; (SEP_CHAR
!= *q
) && (q
> name
); q
--);
192 /* Didn't find separator */
193 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
194 "Could not find domain in map path %s", name
);
198 map
->domain
= (char *)am(myself
, p
- q
);
199 if (NULL
== map
->domain
) {
200 logmsg(MSG_NOMEM
, LOG_ERR
,
201 "Could not alloc memory for domain in path %s", name
);
204 (void) strncpy(map
->domain
, q
+ 1, p
-q
-1);
205 map
->domain
[p
-q
-1] = '\0';
207 /* Work out extra names required by N2L */
210 * Work out what old style NIS path would have been. This is
211 * used to check for date of DBM file so add the DBM
214 map
->trad_map_path
= (char *)am(myself
, strlen(map
->map_name
) +
215 + strlen(dbm_pag
) + (p
- name
) + 2);
216 if (NULL
== map
->trad_map_path
) {
217 logmsg(MSG_NOMEM
, LOG_ERR
,
218 "Could not alocate memory for "
219 "traditional map path derived from %s", name
);
223 strncpy(map
->trad_map_path
, name
, p
- name
+ 1);
224 map
->trad_map_path
[p
- name
+ 1] = '\0';
225 strcat(map
->trad_map_path
, map
->map_name
);
226 strcat(map
->trad_map_path
, dbm_pag
);
228 /* Generate qualified TTL file name */
229 map
->ttl_path
= (char *)am(myself
, strlen(map
->map_path
) +
230 strlen(TTL_POSTFIX
) + 1);
231 if (NULL
== map
->ttl_path
) {
232 logmsg(MSG_NOMEM
, LOG_ERR
,
233 "Could not alocate memory for "
234 "ttl path derived from %s", name
);
238 strcpy(map
->ttl_path
, map
->map_path
);
239 strcat(map
->ttl_path
, TTL_POSTFIX
);
242 /* Work out hash value */
243 map
->hash_val
= hash(name
);
245 /* Set up magic number */
246 map
->magic
= MAP_MAGIC
;
248 /* Null out pointers */
252 /* No key data yet */
253 map
->key_data
.dptr
= NULL
;
254 map
->key_data
.dsize
= 0;
260 * FUNCTION: get_map_crtl();
262 * DESCRIPTION: Find an existing map_ctrl for a map of a given DBM * (i.e.
263 * handle) . If none exists return an error.
267 * OUTPUTS: Pointer to map_ctrl
272 get_map_ctrl(DBM
*db
)
274 /* Check that this really is a map_ctrl not a DBM */
275 if (((map_ctrl
*)db
)->magic
!= MAP_MAGIC
) {
276 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
277 "SHIM called with DBM ptr not map_crtl ptr");
281 /* Since this is an opaque pointer just cast it */
282 return ((map_ctrl
*)db
);
286 * FUNCTION: dup_map_ctrl()
288 * DESCRIPTION: Duplicates a map_ctrl structure
290 * GIVEN : Map_ctrl to duplicate
292 * RETURNS : Pointer to a new malloced map_ctrl. CALLER MUST FREE
296 dup_map_ctrl(map_ctrl
*old_map
)
301 * Could save a little bit of time by duplicating the static parts
302 * of the old map but on balance it is cleaner to just make a new one
305 new_map
= create_map_ctrl(old_map
->map_path
);
310 /* If old map had open handles duplicate them */
311 if (NULL
!= old_map
->entries
) {
312 new_map
->open_flags
= old_map
->open_flags
;
313 new_map
->open_mode
= old_map
->open_mode
;
314 if (FAILURE
== open_yptol_files(new_map
)) {
315 free_map_ctrl(new_map
);
324 * FUNCTION: free_map_crtl();
326 * DESCRIPTION: Free contents of a map_ctr structure and closed any open
329 * INPUTS: Pointer to pointer to a map_ctrl.
335 free_map_ctrl(map_ctrl
*map
)
338 if (NULL
!= map
->entries
) {
339 dbm_close(map
->entries
);
343 if (NULL
!= map
->map_name
) {
344 sfree(map
->map_name
);
345 map
->map_name
= NULL
;
348 if (NULL
!= map
->map_path
) {
349 sfree(map
->map_path
);
350 map
->map_path
= NULL
;
353 if (NULL
!= map
->domain
) {
359 if (NULL
!= map
->ttl
) {
364 if (NULL
!= map
->trad_map_path
) {
365 sfree(map
->trad_map_path
);
366 map
->trad_map_path
= NULL
;
369 if (NULL
!= map
->ttl_path
) {
370 sfree(map
->ttl_path
);
371 map
->ttl_path
= NULL
;
374 if (NULL
!= map
->key_data
.dptr
) {
375 sfree(map
->key_data
.dptr
);
376 map
->key_data
.dptr
= NULL
;
377 map
->key_data
.dsize
= 0;
383 /* Since map_ctrls are now always in malloced memory */
389 * FUNCTION : get_map_name()
391 * DESCRIPTION: Get the name of a map from its map_ctrl. This could be done
392 * as a simple dereference but this function hides the internal
393 * implementation of map_ctrl from higher layers.
395 * GIVEN : A map_ctrl pointer
397 * RETURNS : A pointer to the map_ctrl. Higher levels treat this as an
398 * opaque DBM pointer.
402 get_map_name(DBM
*db
)
404 map_ctrl
*map
= (map_ctrl
*)db
;
409 return (map
->map_name
);
413 * FUNCTION : set_key_data()
415 * DESCRIPTION: Sets up the key data freeing any that already exists.
417 * GIVEN : Pointer to the map_ctrl to set up.
418 * Datum containing the key. The dptr of this will be set to
419 * point to the key data.
424 set_key_data(map_ctrl
*map
, datum
*data
)
426 char *myself
= "set_key_data";
429 * Free up any existing key data. Because each dbm file can only have
430 * one enumeration going at a time this is safe.
432 if (NULL
!= map
->key_data
.dptr
) {
433 sfree(map
->key_data
.dptr
);
434 map
->key_data
.dptr
= NULL
;
435 map
->key_data
.dsize
= 0;
438 /* If nothing in key just return */
439 if (NULL
== data
->dptr
)
442 /* Something is in the key so must duplicate out of static memory */
443 map
->key_data
.dptr
= (char *)am(myself
, data
->dsize
);
444 if (NULL
== map
->key_data
.dptr
) {
445 logmsg(MSG_NOMEM
, LOG_ERR
, "Cannot alloc memory for key data");
447 memcpy(map
->key_data
.dptr
, data
->dptr
, data
->dsize
);
448 map
->key_data
.dsize
= data
->dsize
;
451 /* Set datum to point to malloced version of the data */
452 data
->dptr
= map
->key_data
.dptr
;
459 * FUNCTION : open_yptol_files()
461 * DESCRIPTION: Opens both yptol files for a map. This is called both when a
462 * map is opened and when it is reopened as a result of an update
463 * operation. Must be called with map locked.
465 * GIVEN : Initialized map_ctrl
467 * RETURNS : SUCCESS = Maps opened
468 * FAILURE = Maps not opened (and mess tidied up)
471 open_yptol_files(map_ctrl
*map
)
474 /* Open entries map */
475 map
->entries
= dbm_open(map
->map_path
, map
->open_flags
, map
->open_mode
);
477 if (NULL
== map
->entries
) {
478 /* Maybe we were asked to open a non-existent map. No problem */
483 /* Open TTLs map. Must always be writable */
484 map
->ttl
= dbm_open(map
->ttl_path
, O_RDWR
| O_CREAT
, 0644);
485 if (NULL
== map
->ttl
) {
486 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
487 "Cannot open TTL file %s", map
->ttl_path
);
488 dbm_close(map
->entries
);
498 * FUNCTION : insert_map_in_list()
500 * DESCRIPTION: add a map in map_id_list[]
505 * RETURNS : SUCCESS = map added
506 * FAILURE = map not added
509 insert_map_in_list(char *map_name
, int unique_value
)
512 bool_t yptol_nl_sav
= yptol_newlock
;
513 map_id_elt_t
*new_elt
;
516 * Index in the hash table is computed from the original
517 * hash function: make sure yptol_newlock is set to false.
519 yptol_newlock
= FALSE
;
520 index
= hash(map_name
);
521 yptol_newlock
= yptol_nl_sav
;
523 new_elt
= (map_id_elt_t
*)calloc(1, sizeof (map_id_elt_t
));
524 if (new_elt
== NULL
) {
527 new_elt
->map_name
= strdup(map_name
);
528 if (new_elt
->map_name
== NULL
) { /* strdup() failed */
532 new_elt
->map_id
= unique_value
;
534 if (map_id_list
[index
] == NULL
) {
535 new_elt
->next
= NULL
;
537 new_elt
->next
= map_id_list
[index
];
539 /* insert at begining */
540 map_id_list
[index
] = new_elt
;
545 #ifdef NISDB_LDAP_DEBUG
547 * FUNCTION : dump_map_id_list()
549 * DESCRIPTION: display max_map and dump map_id_list[]
550 * not called, here for debug convenience only
560 map_id_elt_t
*cur_elt
;
562 logmsg(MSG_NOTIMECHECK
, LOG_DEBUG
,
563 "dump_map_id_list: max_map is: %d, dumping map_idlist ...",
566 for (i
= 0; i
< MAXHASH
; i
++) {
567 if (map_id_list
[i
] == NULL
) {
568 logmsg(MSG_NOTIMECHECK
, LOG_DEBUG
,
569 "no map for index %d", i
);
571 logmsg(MSG_NOTIMECHECK
, LOG_DEBUG
,
572 "index %d has the following maps", i
);
573 cur_elt
= map_id_list
[i
];
575 logmsg(MSG_NOTIMECHECK
, LOG_DEBUG
,
579 cur_elt
= cur_elt
->next
;
580 } while (cur_elt
!= NULL
);
587 * FUNCTION : free_map_id_list()
589 * DESCRIPTION: free all previously allocated elements of map_id_list[]
600 map_id_elt_t
*cur_elt
, *next_elt
;
602 for (i
= 0; i
< MAXHASH
; i
++) {
603 if (map_id_list
[i
] != NULL
) {
604 cur_elt
= map_id_list
[i
];
606 next_elt
= cur_elt
->next
;
607 if (cur_elt
->map_name
)
608 sfree(cur_elt
->map_name
);
611 } while (cur_elt
!= NULL
);
612 map_id_list
[i
] = NULL
;
619 * FUNCTION : map_id_list_init()
621 * DESCRIPTION: initializes map_id_list[] and max_map
631 char **domain_list
, **map_list
= NULL
;
634 char *myself
= "map_id_list_init";
635 char mapbuf
[MAXPATHLEN
];
636 int mapbuf_len
= sizeof (mapbuf
);
641 for (i
= 0; i
< MAXHASH
; i
++) {
642 map_id_list
[i
] = NULL
;
645 domain_num
= get_mapping_domain_list(&domain_list
);
646 for (i
= 0; i
< domain_num
; i
++) {
648 free_map_list(map_list
);
652 /* get map list from mapping file */
653 map_list
= get_mapping_map_list(domain_list
[i
]);
654 if (map_list
== NULL
) {
655 /* no map for this domain in mapping file */
656 logmsg(MSG_NOTIMECHECK
, LOG_DEBUG
,
657 "%s: get_mapping_map_list()"
658 " found no map for domain %s",
659 myself
, domain_list
[i
]);
662 /* add maps from /var/yp/<domain> */
663 if (add_map_domain_to_list(domain_list
[i
], &map_list
) ==
665 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
666 "%s: add_map_domain_to_list() failed", myself
);
668 if (map_list
) free_map_list(map_list
);
672 if (map_list
== NULL
|| map_list
[0] == NULL
) {
673 logmsg(MSG_NOTIMECHECK
, LOG_DEBUG
,
674 "%s: no map in domain %s",
675 myself
, domain_list
[i
]);
679 for (j
= 0; map_list
[j
] != NULL
; j
++) {
680 /* build long name */
681 map_name_len
= ypdbpath_sz
+ 1 +
682 strlen(domain_list
[i
]) + 1 +
683 strlen(NTOL_PREFIX
) +
684 strlen(map_list
[j
]) + 1;
685 if (map_name_len
> mapbuf_len
) {
686 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
687 "%s: map name too long for %s",
688 " in domain %s", myself
, map_list
[j
],
691 if (map_list
) free_map_list(map_list
);
694 (void) memset(mapbuf
, 0, mapbuf_len
);
695 (void) snprintf(mapbuf
, map_name_len
, "%s%c%s%c%s%s",
696 ypdbpath
, SEP_CHAR
, domain_list
[i
], SEP_CHAR
,
697 NTOL_PREFIX
, map_list
[j
]);
699 if (insert_map_in_list(mapbuf
, seqnum
)
701 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
702 "%s: failed to insert map %s",
703 " in domain %s", myself
, map_list
[j
]);
705 if (map_list
) free_map_list(map_list
);
714 #ifdef NISDB_LDAP_DEBUG
719 * If more maps than allocated spaces in shared memory, that's a failure
720 * probably need to free previously allocated memory if failure,
723 if (max_map
> MAXHASH
) {
725 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
726 "%s: too many maps (%d)",
730 if (map_list
) free_map_list(map_list
);
735 * FUNCTION : get_list_max()
737 * DESCRIPTION: return references to static variables map_id_list
740 * GIVEN : address for referencing map_id_list
741 * address for referencing max_map
746 get_list_max(map_id_elt_t
***list
, int *max
)