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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <locale.h> /* gettext */ 31 #include <dlfcn.h> 32 #include <string.h> 33 #include <sys/varargs.h> 34 #include <errno.h> 35 #include "nscd_db.h" 36 #include "nscd_config.h" 37 #include "nscd_cfgdef.h" 38 #include "nscd_log.h" 39 40 typedef struct { 41 rwlock_t *global; 42 rwlock_t *alldb; 43 rwlock_t *nswdb; 44 } nscd_cfg_lock_t; 45 46 static rwlock_t cfg_paramDB_rwlock = DEFAULTRWLOCK; 47 static nscd_db_t *cfg_paramDB = NULL; 48 49 static nscd_cfg_global_data_t *nscd_cfg_global_current; 50 static nscd_cfg_nsw_db_data_t *nscd_cfg_nsw_db_data_current; 51 static nscd_cfg_nsw_db_data_t *nscd_cfg_nsw_alldb_current; 52 static rwlock_t *nscd_cfg_global_rwlock; 53 static rwlock_t *nscd_cfg_nsw_db_data_rwlock; 54 static rwlock_t *nscd_cfg_nsw_alldb_rwlock; 55 56 extern int _nscd_cfg_num_nsw_src_all; 57 extern nscd_cfg_id_t *_nscd_cfg_nsw_src_all; 58 59 nscd_cfg_error_t * 60 _nscd_cfg_make_error( 61 nscd_rc_t rc, 62 char *msg) 63 { 64 65 nscd_cfg_error_t *ret; 66 int size, msglen; 67 68 msglen = (msg != NULL ? strlen(msg) + 1 : 0); 69 70 size = sizeof (nscd_cfg_error_t) + msglen; 71 72 ret = calloc(1, size); 73 if (ret == NULL) 74 return (NULL); 75 76 ret->rc = rc; 77 if (msg != NULL) { 78 ret->msg = (char *)ret + 79 sizeof (nscd_cfg_error_t); 80 (void) memcpy(ret->msg, msg, msglen); 81 } 82 83 return (ret); 84 } 85 86 static nscd_rc_t 87 _nscd_cfg_get_list( 88 nscd_cfg_list_t **list, 89 nscd_cfg_list_type_t type) 90 { 91 char *me = "_nscd_cfg_get_list"; 92 int i, num, size; 93 nscd_cfg_id_t *l; 94 nscd_cfg_list_t *ret; 95 nscd_cfg_param_desc_t *pl; 96 nscd_cfg_stat_desc_t *sl; 97 void *p; 98 99 if (list == NULL) { 100 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 101 (me, "invalid argument: list = %p\n", list); 102 103 return (NSCD_INVALID_ARGUMENT); 104 } 105 *list = NULL; 106 107 switch (type) { 108 case NSCD_CFG_LIST_NSW_DB: 109 110 num = _nscd_cfg_num_nsw_db; 111 l = &_nscd_cfg_nsw_db[0]; 112 break; 113 114 case NSCD_CFG_LIST_NSW_SRC: 115 116 num = _nscd_cfg_num_nsw_src_all; 117 l = _nscd_cfg_nsw_src_all; 118 break; 119 120 case NSCD_CFG_LIST_PARAM: 121 122 num = _nscd_cfg_num_param; 123 pl = &_nscd_cfg_param_desc[0]; 124 break; 125 126 case NSCD_CFG_LIST_STAT: 127 128 num = _nscd_cfg_num_stat; 129 sl = &_nscd_cfg_stat_desc[0]; 130 break; 131 132 default: 133 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 134 (me, "invalid argument: type (%d)\n", type); 135 136 return (NSCD_INVALID_ARGUMENT); 137 break; 138 } 139 140 size = sizeof (nscd_cfg_list_t) + sizeof (nscd_cfg_id_t *) * (num + 1); 141 142 ret = calloc(1, size); 143 if (ret == NULL) 144 return (NSCD_NO_MEMORY); 145 146 ret->num = num; 147 p = (char *)ret + sizeof (nscd_cfg_list_t); 148 ret->list = (nscd_cfg_id_t **)p; 149 150 if (type == NSCD_CFG_LIST_PARAM) { 151 for (i = 0; i <= num; i++) 152 ret->list[i] = (nscd_cfg_id_t *)&pl[i]; 153 } else if (type == NSCD_CFG_LIST_STAT) { 154 for (i = 0; i <= num; i++) 155 ret->list[i] = (nscd_cfg_id_t *)&sl[i]; 156 } else { 157 for (i = 0; i <= num; i++) 158 ret->list[i] = &l[i]; 159 } 160 161 *list = ret; 162 163 return (NSCD_SUCCESS); 164 } 165 166 nscd_rc_t 167 _nscd_cfg_get_param_desc_list( 168 nscd_cfg_param_desc_list_t **list) 169 { 170 return (_nscd_cfg_get_list((nscd_cfg_list_t **)list, 171 NSCD_CFG_LIST_PARAM)); 172 } 173 174 /* 175 * FUNCTION: _nscd_cfg_create_paramDB 176 * 177 * Create the internal config parameter database 178 */ 179 static nscd_db_t * 180 _nscd_cfg_create_paramDB() 181 { 182 183 nscd_db_t *ret; 184 185 (void) rw_wrlock(&cfg_paramDB_rwlock); 186 187 ret = _nscd_alloc_db(NSCD_DB_SIZE_MEDIUM); 188 189 if (ret != NULL) 190 cfg_paramDB = ret; 191 192 (void) rw_unlock(&cfg_paramDB_rwlock); 193 194 return (ret); 195 } 196 197 /* 198 * FUNCTION: _nscd_cfg_add_index_entry 199 * 200 * Add a config index entry (a name to index mapping) 201 * to the internal configuration database. 202 */ 203 static nscd_rc_t 204 _nscd_cfg_add_index_entry( 205 char *name, 206 int index, 207 nscd_cfg_list_type_t type) 208 { 209 int *idx; 210 int size; 211 int dbe_type; 212 nscd_db_entry_t *db_entry; 213 214 if (name == NULL) 215 return (NSCD_INVALID_ARGUMENT); 216 217 if (type == NSCD_CFG_LIST_NSW_DB) 218 dbe_type = NSCD_DATA_CFG_NSW_DB_INDEX; 219 else if (type == NSCD_CFG_LIST_NSW_SRC) 220 dbe_type = NSCD_DATA_CFG_NSW_SRC_INDEX; 221 else if (type == NSCD_CFG_LIST_PARAM) 222 dbe_type = NSCD_DATA_CFG_PARAM_INDEX; 223 else if (type == NSCD_CFG_LIST_STAT) 224 dbe_type = NSCD_DATA_CFG_STAT_INDEX; 225 226 size = sizeof (int); 227 228 db_entry = _nscd_alloc_db_entry(dbe_type, (const char *)name, 229 size, 1, 1); 230 if (db_entry == NULL) 231 return (NSCD_NO_MEMORY); 232 233 idx = (int *)*(db_entry->data_array); 234 *idx = index; 235 236 (void) rw_wrlock(&cfg_paramDB_rwlock); 237 (void) _nscd_add_db_entry(cfg_paramDB, name, db_entry, 238 NSCD_ADD_DB_ENTRY_FIRST); 239 (void) rw_unlock(&cfg_paramDB_rwlock); 240 241 return (NSCD_SUCCESS); 242 } 243 244 /* 245 * FUNCTION: _nscd_cfg_get_index 246 * 247 * Get the index of a config data item by searching the internal config 248 * database. Do not free the returned data. 249 */ 250 static int 251 _nscd_cfg_get_index( 252 char *name, 253 nscd_cfg_list_type_t type) 254 { 255 int index = -1, dbe_type; 256 const nscd_db_entry_t *db_entry; 257 258 if (name == NULL) 259 return (-1); 260 261 if (type == NSCD_CFG_LIST_NSW_DB) 262 dbe_type = NSCD_DATA_CFG_NSW_DB_INDEX; 263 else if (type == NSCD_CFG_LIST_NSW_SRC) 264 dbe_type = NSCD_DATA_CFG_NSW_SRC_INDEX; 265 else if (type == NSCD_CFG_LIST_PARAM) 266 dbe_type = NSCD_DATA_CFG_PARAM_INDEX; 267 else if (type == NSCD_CFG_LIST_STAT) 268 dbe_type = NSCD_DATA_CFG_STAT_INDEX; 269 else 270 return (-1); 271 272 db_entry = _nscd_get_db_entry(cfg_paramDB, dbe_type, 273 (const char *)name, NSCD_GET_FIRST_DB_ENTRY, 0); 274 275 if (db_entry != NULL) 276 index = *(int *)*(db_entry->data_array); 277 278 return (index); 279 } 280 281 static nscd_rc_t 282 _nscd_cfg_verify_group_info( 283 nscd_cfg_group_info_t *g_info, 284 nscd_cfg_param_desc_t *gdesc) 285 { 286 287 char *me = "_nscd_cfg_verify_group_info"; 288 void *vp; 289 nscd_cfg_group_info_t *gi; 290 291 if (_nscd_cfg_flag_is_set(gdesc->pflag, NSCD_CFG_PFLAG_GLOBAL)) { 292 vp = (char *)&nscd_cfg_global_default + 293 gdesc->g_offset; 294 gi = (nscd_cfg_group_info_t *)vp; 295 } else { 296 vp = (char *)&nscd_cfg_nsw_db_data_default + 297 gdesc->g_offset; 298 gi = (nscd_cfg_group_info_t *)vp; 299 300 } 301 302 if (g_info->num_param == gi->num_param && 303 _nscd_cfg_bitmap_is_equal(g_info->bitmap, gi->bitmap)) 304 return (NSCD_SUCCESS); 305 306 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 307 (me, "ERROR: group (%s) info mismatched: group info " 308 "(%d, %#6.4x) not equal to that of default configuration data " 309 "(%d, %#6.4x)\n", gdesc->id.name, g_info->num_param, 310 _nscd_cfg_bitmap_value(g_info->bitmap), gi->num_param, 311 _nscd_cfg_bitmap_value(gi->bitmap)); 312 313 return (NSCD_CFG_PARAM_DESC_ERROR); 314 315 } 316 317 318 static nscd_rc_t 319 _nscd_cfg_init_nsw() 320 { 321 char *me = "_nscd_cfg_init_nsw"; 322 int i, j, idx, rc, num; 323 nscd_cfg_id_t *id; 324 nscd_cfg_list_type_t type[2] = { NSCD_CFG_LIST_NSW_DB, 325 NSCD_CFG_LIST_NSW_SRC }; 326 327 nscd_cfg_id_t *list[2] = { _nscd_cfg_nsw_db, NULL}; 328 329 list[1] = _nscd_cfg_nsw_src_all; 330 331 for (j = 0; j < 2; j++) { 332 333 if (j == 0) 334 num = _nscd_cfg_num_nsw_db + 1; 335 else 336 num = _nscd_cfg_num_nsw_src_all; 337 338 for (i = 0; i < num; i++) { 339 340 /* 341 * _nscd_cfg_nsw_alldb is the id for the 342 * special ALLDB (defaults for all db) 343 */ 344 if (j == 0 && i == _nscd_cfg_num_nsw_db) { 345 id = &_nscd_cfg_nsw_alldb; 346 idx = NSCD_CFG_NSW_ALLDB_INDEX; 347 } else { 348 id = &(list[j])[i]; 349 id->index = idx = i; 350 } 351 352 if (id->name == NULL) 353 continue; 354 355 if ((rc = _nscd_cfg_add_index_entry(id->name, 356 idx, type[j])) != NSCD_SUCCESS) { 357 358 _NSCD_LOG(NSCD_LOG_CONFIG, 359 NSCD_LOG_LEVEL_ERROR) 360 (me, "unable to add index entry for " 361 "nsswitch entry %s\n", id->name); 362 363 _nscd_free_db(cfg_paramDB); 364 return (rc); 365 } 366 } 367 } 368 369 return (NSCD_SUCCESS); 370 } 371 372 static nscd_rc_t 373 _nscd_cfg_init_param() 374 { 375 char *me = "_nscd_cfg_init_param"; 376 int i, gi, fn = 0; 377 nscd_cfg_id_t *id; 378 nscd_cfg_param_desc_t *desc, *gdesc = NULL; 379 nscd_cfg_group_info_t g_info; 380 nscd_cfg_list_type_t type = NSCD_CFG_LIST_PARAM; 381 nscd_rc_t rc; 382 void *nfunc, *vfunc; 383 384 if (_nscd_cfg_create_paramDB() == NULL) 385 return (NSCD_NO_MEMORY); 386 387 desc = &_nscd_cfg_param_desc[0]; 388 389 /* 390 * need to loop to the last (+1) param description 391 * which is a fake group and which marks the end 392 * of list. It is used to signal the end of the 393 * previous group so that the proper data will be 394 * set for that group 395 */ 396 for (i = 0; i < _nscd_cfg_num_param + 1; i++, desc++) { 397 398 id = (nscd_cfg_id_t *)desc; 399 400 if (_nscd_cfg_flag_is_set(desc->pflag, 401 NSCD_CFG_PFLAG_GROUP)) { 402 403 if (gdesc != NULL) { 404 g_info.num_param = fn; 405 gdesc->p_fn = fn; 406 407 if ((rc = _nscd_cfg_verify_group_info( 408 &g_info, gdesc)) != NSCD_SUCCESS) 409 return (rc); 410 } 411 412 gi = i; 413 fn = 0; 414 gdesc = desc; 415 g_info.bitmap = NSCD_CFG_BITMAP_ZERO; 416 417 /* 418 * set the notify/verify functions 419 */ 420 nfunc = (void *)gdesc->notify; 421 vfunc = (void *)gdesc->verify; 422 } else { 423 if (i == 0) { 424 425 _NSCD_LOG(NSCD_LOG_CONFIG, 426 NSCD_LOG_LEVEL_ERROR) 427 (me, "ERROR: first parameter " 428 "description is not for a group\n"); 429 430 return (NSCD_CFG_PARAM_DESC_ERROR); 431 } 432 433 /* 434 * set bitmap: the rightmost bit represents 435 * the first member (index = 0) in the group, 436 * the next bit is for the second member 437 * (index = 1), and so on 438 */ 439 _nscd_cfg_bitmap_set_nth(g_info.bitmap, fn); 440 441 desc->p_fn = fn++; 442 443 /* 444 * set the notify/verify functions 445 */ 446 if (desc->notify == NSCD_CFG_FUNC_NOTIFY_AS_GROUP) { 447 (void) memcpy(&desc->notify, &nfunc, 448 sizeof (void *)); 449 } 450 if (desc->verify == NSCD_CFG_FUNC_VERIFY_AS_GROUP) { 451 (void) memcpy(&desc->verify, &vfunc, 452 sizeof (void *)); 453 } 454 } 455 456 /* if end of list reached, we are done */ 457 if (i == _nscd_cfg_num_param) 458 break; 459 460 desc->g_index = gi; 461 462 id->index = i; 463 464 if ((rc = _nscd_cfg_add_index_entry(id->name, 465 i, type)) != NSCD_SUCCESS) { 466 467 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 468 (me, "unable to add index entry for parameter " 469 "%s\n", id->name); 470 471 _nscd_free_db(cfg_paramDB); 472 return (rc); 473 } else { 474 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 475 (me, "index entry for parameter " 476 "%s added\n", id->name); 477 } 478 } 479 480 return (_nscd_cfg_init_nsw()); 481 } 482 483 static nscd_rc_t 484 _nscd_cfg_init_stat() 485 { 486 char *me = "_nscd_cfg_init_stat"; 487 int i, gi, fn = 0; 488 nscd_cfg_id_t *id; 489 nscd_cfg_stat_desc_t *desc, *gdesc = NULL; 490 nscd_cfg_group_info_t g_info; 491 nscd_cfg_list_type_t type = NSCD_CFG_LIST_STAT; 492 nscd_rc_t rc; 493 void *gsfunc; 494 495 desc = &_nscd_cfg_stat_desc[0]; 496 497 /* 498 * need to loop to the last (+1) stat description 499 * which is a fake group and which marks the end 500 * of list. It is used to signal the end of the 501 * previous group so that the proper data will be 502 * set for that group 503 */ 504 for (i = 0; i < _nscd_cfg_num_stat + 1; i++, desc++) { 505 506 id = (nscd_cfg_id_t *)desc; 507 508 if (_nscd_cfg_flag_is_set(desc->sflag, 509 NSCD_CFG_SFLAG_GROUP)) { 510 511 if (gdesc != NULL) { 512 g_info.num_param = fn; 513 gdesc->s_fn = fn; 514 515 if (g_info.num_param != 516 gdesc->gi.num_param || 517 !_nscd_cfg_bitmap_is_equal( 518 g_info.bitmap, gdesc->gi.bitmap)) { 519 520 _NSCD_LOG(NSCD_LOG_CONFIG, 521 NSCD_LOG_LEVEL_ERROR) 522 (me, "ERROR: group (%s) " 523 "info mismatched: " 524 "group info (%d, %#6.4x) not " 525 "equal to the predefined one " 526 "(%d, %#6.4x)\n", gdesc->id.name, 527 g_info.num_param, 528 _nscd_cfg_bitmap_value(g_info.bitmap), 529 gdesc->gi.num_param, 530 _nscd_cfg_bitmap_value( 531 gdesc->gi.bitmap)); 532 533 exit(1); 534 return (NSCD_CFG_STAT_DESC_ERROR); 535 } 536 } 537 538 gi = i; 539 fn = 0; 540 gdesc = desc; 541 g_info.bitmap = NSCD_CFG_BITMAP_ZERO; 542 543 /* 544 * set the get_stat function 545 */ 546 gsfunc = (void *)gdesc->get_stat; 547 } else { 548 if (i == 0) { 549 550 _NSCD_LOG(NSCD_LOG_CONFIG, 551 NSCD_LOG_LEVEL_ERROR) 552 (me, "ERROR: first stat " 553 "description is not for a group\n"); 554 555 return (NSCD_CFG_STAT_DESC_ERROR); 556 } 557 558 /* 559 * set bitmap: the rightmost bit represents 560 * the first member (index = 0) in the group, 561 * the next bit is for the second member 562 * (index = 1), and so on 563 */ 564 _nscd_cfg_bitmap_set_nth(g_info.bitmap, fn); 565 566 desc->s_fn = fn++; 567 568 /* 569 * set the get_stat function 570 */ 571 if (desc->get_stat == NSCD_CFG_FUNC_GET_STAT_AS_GROUP) { 572 (void) memcpy(&desc->get_stat, &gsfunc, 573 sizeof (void *)); 574 } 575 } 576 577 /* if end of list reached, we are done */ 578 if (i == _nscd_cfg_num_stat) 579 break; 580 581 desc->g_index = gi; 582 583 id->index = i; 584 585 if ((rc = _nscd_cfg_add_index_entry(id->name, 586 i, type)) != NSCD_SUCCESS) { 587 588 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 589 (me, "unable to add index entry for stat " 590 "description %s\n", id->name); 591 592 _nscd_free_db(cfg_paramDB); 593 return (rc); 594 } else { 595 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 596 (me, "index entry for stat description " 597 "%s added\n", id->name); 598 } 599 } 600 601 return (NSCD_SUCCESS); 602 } 603 604 static nscd_rc_t 605 _nscd_cfg_copy_vlen_data( 606 void *data, 607 void **new_data_p, 608 nscd_cfg_param_desc_t *desc, 609 int *data_len, 610 nscd_bool_t in) 611 { 612 int len, dlen; 613 nscd_cfg_vlen_data_t *v = NULL; 614 615 *new_data_p = NULL; 616 *data_len = 0; 617 618 /* it is OK if there is nothing to copy */ 619 if (data == NULL) 620 return (NSCD_SUCCESS); 621 622 /* 623 * if copy to the config store we need to allocate space 624 * for the extra vlen header 625 */ 626 if (desc->type == NSCD_CFG_DATA_STRING) { 627 len = dlen = strlen((char *)data) + 1; 628 if (in == nscd_true) 629 len += sizeof (nscd_cfg_vlen_data_t); 630 } else { 631 /* 632 * should not be here, since for now 633 * only string variable length data 634 * is supported 635 */ 636 *new_data_p = NULL; 637 return (NSCD_CFG_PARAM_DESC_ERROR); 638 } 639 640 v = calloc(1, len); 641 if (v == NULL) { 642 *new_data_p = NULL; 643 return (NSCD_NO_MEMORY); 644 } 645 646 /* 647 * if copy to the config store, set up 648 * the extra vlen header in which the 649 * pointer to, and length of, the real 650 * data are kept. The pointer to the real 651 * data, not the vlen header, is returned. 652 */ 653 if (in == nscd_true) { 654 v->ptr = (char *)v + sizeof (nscd_cfg_vlen_data_t); 655 v->len = dlen; 656 (void) memcpy(v->ptr, data, dlen); 657 *new_data_p = v->ptr; 658 } else { 659 (void) memcpy(v, data, dlen); 660 *new_data_p = v; 661 } 662 *data_len = dlen; 663 664 return (NSCD_SUCCESS); 665 } 666 667 static void 668 _nscd_cfg_free_vlen_data_int( 669 void *data) 670 { 671 nscd_cfg_vlen_data_t *v = NULL; 672 void *p; 673 674 if (data == NULL) 675 return; 676 677 p = (char *)data - sizeof (nscd_cfg_vlen_data_t); 678 v = (nscd_cfg_vlen_data_t *)p; 679 if (v->ptr == data) 680 free(v); 681 } 682 683 static nscd_rc_t 684 _nscd_cfg_set_vlen_data_int( 685 void *src, 686 void *dest, 687 nscd_bool_t global) 688 { 689 int i, offset, dlen = 0; 690 void *s, *d, *new; 691 void *cptr; 692 nscd_rc_t rc; 693 nscd_cfg_param_desc_t *desc; 694 695 desc = &_nscd_cfg_param_desc[0]; 696 for (i = 0; i < _nscd_cfg_num_param; i++, desc++) { 697 698 if (global == nscd_true && 699 _nscd_cfg_flag_is_not_set(desc->pflag, 700 NSCD_CFG_PFLAG_GLOBAL)) 701 continue; 702 else if (global != nscd_true && 703 _nscd_cfg_flag_is_set(desc->pflag, 704 NSCD_CFG_PFLAG_GLOBAL)) 705 continue; 706 707 if (_nscd_cfg_flag_is_set(desc->pflag, 708 NSCD_CFG_PFLAG_VLEN_DATA)) { 709 710 offset = desc->g_offset + desc->p_offset; 711 712 s = (char *)src + offset; 713 cptr = *(char **)s; 714 715 rc = _nscd_cfg_copy_vlen_data(cptr, &new, 716 desc, &dlen, nscd_true); 717 if (rc != NSCD_SUCCESS) 718 return (rc); 719 720 d = (char *)dest + offset; 721 /* free the old vlen data */ 722 if (*(char **)d == NULL) 723 _nscd_cfg_free_vlen_data_int(*(char **)d); 724 725 *(char **)d = new; 726 } 727 } 728 729 return (NSCD_SUCCESS); 730 } 731 732 static void * 733 _nscd_cfg_locate_vlen_data( 734 void *cfg_data, 735 int *len) 736 { 737 void *ptr, *ret; 738 739 ptr = *(char **)cfg_data; 740 ret = ptr; 741 if (ret == NULL) { 742 *len = 0; 743 return (NULL); 744 } 745 ptr = (char *)ptr - sizeof (nscd_cfg_vlen_data_t); 746 *len = ((nscd_cfg_vlen_data_t *)ptr)->len; 747 748 return (ret); 749 } 750 751 static void 752 _nscd_cfg_lock( 753 nscd_bool_t is_read, 754 nscd_cfg_lock_t *cfglock) 755 { 756 757 int (*lockfunc)(rwlock_t *); 758 759 if (cfglock == NULL) 760 return; 761 762 if (is_read == nscd_true) 763 lockfunc = rw_rdlock; 764 else 765 lockfunc = rw_wrlock; 766 767 if (cfglock->global != NULL) { 768 769 (lockfunc)(cfglock->global); 770 return; 771 } 772 773 if (cfglock->alldb != NULL) 774 (lockfunc)(cfglock->alldb); 775 776 if (cfglock->nswdb != NULL) 777 (lockfunc)(cfglock->nswdb); 778 } 779 780 static void 781 _nscd_cfg_unlock( 782 nscd_cfg_lock_t *cfglock) 783 { 784 if (cfglock == NULL) 785 return; 786 787 if (cfglock->global != NULL) { 788 789 (void) rw_unlock(cfglock->global); 790 free(cfglock); 791 return; 792 } 793 794 if (cfglock->nswdb != NULL) 795 (void) rw_unlock(cfglock->nswdb); 796 797 if (cfglock->alldb != NULL) 798 (void) rw_unlock(cfglock->alldb); 799 800 free(cfglock); 801 } 802 803 /* 804 * If vlen_data_addr is given, it will be set to the 805 * address of the pointer pointing to the vlen data. 806 * 'cfglock' will be set to point to the reader/writer 807 * lock(s) protecting the (group) configuration data. 808 */ 809 static nscd_rc_t 810 _nscd_cfg_locate_cfg_data( 811 void **cfg_data, 812 nscd_bool_t is_read, 813 nscd_cfg_param_desc_t *desc, 814 nscd_cfg_id_t *nswdb, 815 nscd_bool_t get_group, 816 void **vlen_data_addr, 817 int *len, 818 nscd_cfg_lock_t **cfglock) 819 { 820 int offset; 821 822 *cfg_data = NULL; 823 if (len != NULL) 824 *len = 0; 825 if (vlen_data_addr != NULL) 826 *vlen_data_addr = NULL; 827 828 if (cfglock != NULL) { 829 *cfglock = calloc(1, sizeof (nscd_cfg_lock_t)); 830 if (*cfglock == NULL) 831 return (NSCD_NO_MEMORY); 832 } 833 834 /* assume if nswdb is NULL, the param is a global one */ 835 if (nswdb == NULL) { 836 837 offset = desc->g_offset; 838 if (get_group != nscd_true) 839 offset += desc->p_offset; 840 *cfg_data = (char *)nscd_cfg_global_current + offset; 841 842 if (cfglock != NULL) 843 (*cfglock)->global = nscd_cfg_global_rwlock; 844 845 } else if (nswdb->index == NSCD_CFG_NSW_ALLDB_INDEX) { 846 847 offset = desc->g_offset; 848 if (get_group != nscd_true) 849 offset += desc->p_offset; 850 *cfg_data = (char *)nscd_cfg_nsw_alldb_current + 851 offset; 852 853 if (cfglock != NULL) 854 (*cfglock)->alldb = nscd_cfg_nsw_alldb_rwlock; 855 856 } else { 857 858 offset = nswdb->index * 859 (sizeof (nscd_cfg_nsw_db_data_t)) + desc->g_offset; 860 if (get_group != nscd_true) 861 offset += desc->p_offset; 862 *cfg_data = (char *)nscd_cfg_nsw_db_data_current + 863 offset; 864 865 if (cfglock != NULL) { 866 (*cfglock)->nswdb = 867 &nscd_cfg_nsw_db_data_rwlock[nswdb->index]; 868 869 (*cfglock)->alldb = nscd_cfg_nsw_alldb_rwlock; 870 } 871 } 872 873 /* lock the config data */ 874 if (cfglock != NULL) 875 _nscd_cfg_lock(is_read, *cfglock); 876 877 if (get_group != nscd_true && 878 _nscd_cfg_flag_is_not_set(desc->pflag, 879 NSCD_CFG_PFLAG_GROUP) && 880 (_nscd_cfg_flag_is_set(desc->pflag, 881 NSCD_CFG_PFLAG_VLEN_DATA))) { 882 if (vlen_data_addr != NULL) 883 *vlen_data_addr = *cfg_data; 884 *cfg_data = _nscd_cfg_locate_vlen_data(*cfg_data, len); 885 return (NSCD_SUCCESS); 886 } 887 888 if (len != NULL) { 889 if (get_group == nscd_true) 890 *len = desc->g_size; 891 else 892 *len = desc->p_size; 893 } 894 895 return (NSCD_SUCCESS); 896 } 897 898 /* 899 * perform the preliminary (range) check on 'data' based on the 900 * datatype (desc->datatype) of the config parameter 901 */ 902 nscd_rc_t 903 _nscd_cfg_prelim_check( 904 nscd_cfg_param_desc_t *desc, 905 void *data, 906 nscd_cfg_error_t **errorp) 907 { 908 909 char *me = "_nscd_cfg_prelim_check"; 910 char msg[NSCD_CFG_MAX_ERR_MSG_LEN]; 911 nscd_cfg_str_check_t *sc; 912 nscd_cfg_int_check_t *ic; 913 nscd_cfg_bitmap_check_t *bmc; 914 nscd_rc_t rc = NSCD_CFG_PRELIM_CHECK_FAILED; 915 916 if ((nscd_cfg_str_check_t *)desc->p_check == NULL) 917 return (NSCD_SUCCESS); 918 919 switch (desc->type) { 920 921 case NSCD_CFG_DATA_STRING: 922 923 sc = (nscd_cfg_str_check_t *)desc->p_check; 924 if (sc->must_not_null == nscd_true && data == NULL) { 925 926 if (errorp == NULL) 927 break; 928 929 (void) snprintf(msg, sizeof (msg), 930 gettext("data must be specified for %s"), 931 desc->id.name); 932 933 break; 934 } 935 936 if (data == NULL) { 937 rc = NSCD_SUCCESS; 938 break; 939 } 940 941 if (sc->maxlen != 0 && 942 strlen((char *)data) > sc->maxlen) { 943 944 if (errorp == NULL) 945 break; 946 947 (void) snprintf(msg, sizeof (msg), 948 gettext("length of data (%s) for %s larger than %d"), 949 (char *)data, desc->id.name, sc->maxlen); 950 break; 951 } 952 953 rc = NSCD_SUCCESS; 954 955 break; 956 957 case NSCD_CFG_DATA_INTEGER: 958 959 ic = (nscd_cfg_int_check_t *)desc->p_check; 960 if (*(int *)data > ic->max || 961 *(int *)data < ic->min) { 962 963 if (errorp == NULL) 964 break; 965 966 (void) snprintf(msg, sizeof (msg), 967 gettext("data (%d) for %s out of range (%d - %d)"), 968 *(int *)data, desc->id.name, 969 ic->min, ic->max); 970 971 break; 972 } 973 974 rc = NSCD_SUCCESS; 975 976 break; 977 978 case NSCD_CFG_DATA_BITMAP: 979 980 bmc = (nscd_cfg_bitmap_check_t *)desc->p_check; 981 if (_nscd_cfg_bitmap_value(*(nscd_cfg_bitmap_t *)data) & 982 ~(bmc->valid_bits)) { 983 984 if (errorp == NULL) 985 break; 986 987 (void) snprintf(msg, sizeof (msg), 988 gettext("data (%#6.4x) for %s contain bit not in 0x%x"), 989 _nscd_cfg_bitmap_value( 990 *(nscd_cfg_bitmap_t *)data), 991 desc->id.name, 992 _nscd_cfg_bitmap_value(bmc->valid_bits)); 993 break; 994 } 995 996 rc = NSCD_SUCCESS; 997 998 break; 999 } 1000 1001 if (rc != NSCD_SUCCESS && errorp != NULL) { 1002 *errorp = _nscd_cfg_make_error(rc, msg); 1003 1004 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 1005 (me, "invalid argument: %s\n", (*errorp)->msg); 1006 } 1007 1008 return (rc); 1009 } 1010 1011 static nscd_rc_t 1012 _nscd_cfg_notify_i( 1013 nscd_cfg_param_desc_t *desc, 1014 nscd_cfg_id_t *nswdb, 1015 int *skip, 1016 nscd_cfg_error_t **errorp) 1017 { 1018 1019 char *me = "_nscd_cfg_notify_i"; 1020 int i, num, skip_bk; 1021 void *cfg_data, *cdata; 1022 void *cookie = NULL; 1023 nscd_rc_t rc; 1024 nscd_cfg_flag_t dflag, dflag1; 1025 nscd_cfg_bitmap_t bitmap_c, bitmap_s, *bitmap_addr; 1026 nscd_cfg_group_info_t *gi; 1027 1028 if (errorp != NULL) 1029 *errorp = NULL; 1030 1031 if (skip == NULL) 1032 skip = &skip_bk; 1033 1034 *skip = 0; 1035 1036 if (_nscd_cfg_flag_is_not_set(desc->pflag, 1037 NSCD_CFG_PFLAG_GROUP)) { 1038 1039 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 1040 (me, "ERROR: expect parameter description for group, " 1041 "but receive parameter description is for %s\n", 1042 desc->id.name); 1043 1044 return (NSCD_CFG_PARAM_DESC_ERROR); 1045 } 1046 1047 /* 1048 * Set data flag going with data to be sent to the 1049 * verify/notify routines. Allowing the config flag 1050 * be exipandable, set the bits one by one. 1051 */ 1052 dflag = NSCD_CFG_FLAG_ZERO; 1053 dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_STATIC_DATA); 1054 dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_INIT); 1055 dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_GROUP); 1056 if (_nscd_cfg_flag_is_set(desc->pflag, 1057 NSCD_CFG_PFLAG_INIT_SET_ALL_DB)) 1058 dflag = _nscd_cfg_flag_set(dflag, 1059 NSCD_CFG_DFLAG_SET_ALL_DB); 1060 1061 /* get to the group data in the config store */ 1062 rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_true, 1063 desc, nswdb, nscd_true, NULL, NULL, NULL); 1064 if (rc != NSCD_SUCCESS) 1065 goto error; 1066 1067 /* 1068 * the static bitmap associated with the group 1069 * may be replaced before sending to the components, 1070 * so save the bitmap for later use 1071 */ 1072 gi = _nscd_cfg_get_gi(cfg_data); 1073 bitmap_c = gi->bitmap; 1074 bitmap_addr = &(gi->bitmap); 1075 1076 /* 1077 * the elements in this group will all be handled 1078 * so the caller can skip them 1079 */ 1080 *skip = desc->p_fn; 1081 1082 if (_nscd_cfg_flag_is_set(desc->pflag, 1083 NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP)) 1084 /* send the entire group just once */ 1085 num = 1; 1086 1087 else { /* send individual members one by one */ 1088 1089 num = desc->p_fn; 1090 1091 /* 1092 * skip the first desc which is for the group 1093 * and get to the desc for the first member 1094 */ 1095 desc++; 1096 1097 dflag = _nscd_cfg_flag_unset(dflag, 1098 NSCD_CFG_DFLAG_GROUP); 1099 } 1100 1101 dflag1 = dflag; 1102 for (i = 0; i < num; i++, desc++) { 1103 1104 dflag = dflag1; 1105 1106 if (_nscd_cfg_flag_is_set(desc->pflag, 1107 NSCD_CFG_PFLAG_SEND_BIT_SELECTED)) { 1108 1109 /* set the bitmap to select just this member */ 1110 bitmap_s = NSCD_CFG_BITMAP_ZERO; 1111 _nscd_cfg_bitmap_set_nth(bitmap_s, i); 1112 /* replace the bitmap in the cfg data */ 1113 _nscd_cfg_bitmap_set(bitmap_addr, bitmap_s); 1114 1115 /* 1116 * send the whole group but with only one 1117 * member selected 1118 */ 1119 cdata = cfg_data; 1120 1121 dflag = _nscd_cfg_flag_set(dflag, 1122 NSCD_CFG_DFLAG_GROUP); 1123 dflag = _nscd_cfg_flag_set(dflag, 1124 NSCD_CFG_DFLAG_BIT_SELECTED); 1125 } else { 1126 /* 1127 * send param data or group data: 1128 * param data - non-xero desc->p_offset 1129 * group data - zero desc->p_offset 1130 */ 1131 cdata = (char *)cfg_data + desc->p_offset; 1132 1133 /* 1134 * if variable length data, need to send pointer 1135 * to the data (not the address of the pointer) 1136 */ 1137 if (_nscd_cfg_flag_is_set(desc->pflag, 1138 NSCD_CFG_PFLAG_VLEN_DATA)) 1139 cdata = *(char **)cdata; 1140 } 1141 1142 if (desc->verify != NULL) { 1143 dflag = _nscd_cfg_flag_set(dflag, 1144 NSCD_CFG_DFLAG_VERIFY); 1145 rc = desc->verify(cdata, desc, nswdb, 1146 dflag, errorp, &cookie); 1147 if (rc != NSCD_SUCCESS) 1148 goto error; 1149 } 1150 1151 if (desc->notify != NULL) { 1152 dflag = _nscd_cfg_flag_set(dflag, 1153 NSCD_CFG_DFLAG_NOTIFY); 1154 1155 rc = desc->notify(cfg_data, desc, nswdb, 1156 dflag, errorp, cookie); 1157 if (rc != NSCD_SUCCESS) 1158 goto error; 1159 } 1160 } 1161 1162 rc = NSCD_SUCCESS; 1163 1164 /* restore the bitmap in the cfg data */ 1165 _nscd_cfg_bitmap_set(bitmap_addr, bitmap_c); 1166 1167 error: 1168 1169 return (rc); 1170 1171 } 1172 1173 static nscd_rc_t 1174 _nscd_cfg_notify_init( 1175 nscd_cfg_error_t **errorp) 1176 { 1177 int i, j, skip; 1178 nscd_rc_t rc; 1179 nscd_cfg_id_t *nswdb = NULL; 1180 nscd_cfg_param_desc_t *desc; 1181 1182 if (errorp != NULL) 1183 *errorp = NULL; 1184 1185 for (i = 0; i < _nscd_cfg_num_param; i++) { 1186 1187 desc = &_nscd_cfg_param_desc[i]; 1188 1189 if (_nscd_cfg_flag_is_set(desc->pflag, 1190 NSCD_CFG_PFLAG_GLOBAL)) { /* global cfg data */ 1191 1192 rc = _nscd_cfg_notify_i(desc, NULL, &skip, errorp); 1193 } else { 1194 1195 /* 1196 * if use defaults for all nsswitch database, 1197 * send the config data to verify/notify once 1198 */ 1199 if (_nscd_cfg_flag_is_set(desc->pflag, 1200 NSCD_CFG_PFLAG_INIT_SET_ALL_DB)) { 1201 1202 nswdb = &_nscd_cfg_nsw_alldb; 1203 1204 rc = _nscd_cfg_notify_i(desc, nswdb, 1205 &skip, errorp); 1206 } else { /* send data once for each nsw db */ 1207 1208 for (j = 0; j < _nscd_cfg_num_nsw_db; j++) { 1209 1210 nswdb = &_nscd_cfg_nsw_db[j]; 1211 1212 rc = _nscd_cfg_notify_i(desc, 1213 nswdb, &skip, errorp); 1214 1215 if (rc != NSCD_SUCCESS) 1216 break; 1217 } 1218 } 1219 } 1220 1221 if (rc != NSCD_SUCCESS) 1222 return (rc); 1223 1224 i += skip; 1225 } 1226 1227 return (NSCD_SUCCESS); 1228 } 1229 1230 nscd_rc_t 1231 _nscd_cfg_init( 1232 nscd_cfg_error_t **errorp) 1233 { 1234 1235 int i, j, datalen; 1236 int dbi = 0, dbj = 0; 1237 char *dest, *src; 1238 char *dbni = NULL, *dbnj = NULL; 1239 nscd_rc_t rc; 1240 nscd_cfg_nsw_spc_default_t *spc; 1241 1242 if (errorp != NULL) 1243 *errorp = NULL; 1244 1245 rc = _nscd_cfg_init_param(); 1246 if (rc != NSCD_SUCCESS) 1247 return (rc); 1248 1249 rc = _nscd_cfg_init_stat(); 1250 if (rc != NSCD_SUCCESS) 1251 return (rc); 1252 1253 nscd_cfg_global_current = calloc(1, 1254 sizeof (nscd_cfg_global_data_t)); 1255 if (nscd_cfg_global_current == NULL) 1256 return (NSCD_NO_MEMORY); 1257 1258 nscd_cfg_nsw_alldb_current = calloc(1, 1259 sizeof (nscd_cfg_nsw_db_data_t)); 1260 if (nscd_cfg_nsw_alldb_current == NULL) 1261 return (NSCD_NO_MEMORY); 1262 1263 nscd_cfg_nsw_db_data_current = calloc(_nscd_cfg_num_nsw_db, 1264 sizeof (nscd_cfg_nsw_db_data_t)); 1265 if (nscd_cfg_nsw_db_data_current == NULL) 1266 return (NSCD_NO_MEMORY); 1267 1268 nscd_cfg_global_rwlock = calloc(1, sizeof (rwlock_t)); 1269 if (nscd_cfg_global_rwlock == NULL) 1270 return (NSCD_NO_MEMORY); 1271 (void) rwlock_init(nscd_cfg_global_rwlock, NULL, NULL); 1272 1273 *nscd_cfg_global_current = nscd_cfg_global_default; 1274 1275 rc = _nscd_cfg_set_vlen_data_int(&nscd_cfg_global_default, 1276 nscd_cfg_global_current, nscd_true); 1277 if (rc != NSCD_SUCCESS) 1278 return (rc); 1279 1280 nscd_cfg_nsw_db_data_rwlock = calloc(_nscd_cfg_num_nsw_db, 1281 sizeof (rwlock_t)); 1282 if (nscd_cfg_nsw_db_data_rwlock == NULL) 1283 return (NSCD_NO_MEMORY); 1284 1285 /* set per switch db config to the default for all db's */ 1286 for (i = 0; i < _nscd_cfg_num_nsw_db; i++) { 1287 1288 nscd_cfg_nsw_db_data_current[i] = 1289 nscd_cfg_nsw_db_data_default; 1290 1291 (void) rwlock_init(&nscd_cfg_nsw_db_data_rwlock[i], 1292 NULL, NULL); 1293 } 1294 1295 /* add db specific defaults */ 1296 for (i = 0; i < _nscd_cfg_num_nsw_default; i++) { 1297 1298 if (_nscd_cfg_nsw_spc_default[i].data == NULL) 1299 continue; 1300 1301 if (_nscd_cfg_nsw_spc_default[i].db != dbni) { 1302 for (j = 0; j < _nscd_cfg_num_nsw_db; j++) { 1303 1304 if (strcmp(_nscd_cfg_nsw_db[j].name, 1305 _nscd_cfg_nsw_spc_default[i].db) != 0) 1306 continue; 1307 1308 dbi = _nscd_cfg_nsw_db[j].index; 1309 dbni = _nscd_cfg_nsw_db[j].name; 1310 break; 1311 } 1312 } 1313 1314 dest = (char *)&nscd_cfg_nsw_db_data_current[dbi] + 1315 _nscd_cfg_nsw_spc_default[i].group_off + 1316 _nscd_cfg_nsw_spc_default[i].param_off; 1317 1318 src = _nscd_cfg_nsw_spc_default[i].data; 1319 datalen = _nscd_cfg_nsw_spc_default[i].data_len; 1320 1321 (void) memcpy(dest, src, datalen); 1322 } 1323 1324 /* add db specific defaults via links */ 1325 for (i = 0; i < _nscd_cfg_num_link_default; i++) { 1326 1327 if (_nscd_cfg_nsw_link_default[i].data == NULL) 1328 continue; 1329 1330 spc = _nscd_cfg_nsw_link_default[i].data; 1331 1332 if (_nscd_cfg_nsw_link_default[i].db != dbni) { 1333 for (j = 0; j < _nscd_cfg_num_nsw_db; j++) { 1334 1335 if (strcmp(_nscd_cfg_nsw_db[j].name, 1336 _nscd_cfg_nsw_link_default[i].db) != 0) 1337 continue; 1338 1339 dbi = _nscd_cfg_nsw_db[j].index; 1340 dbni = _nscd_cfg_nsw_db[j].name; 1341 break; 1342 } 1343 } 1344 1345 dest = (char *)&nscd_cfg_nsw_db_data_current[dbi] + 1346 _nscd_cfg_nsw_link_default[i].group_off + 1347 _nscd_cfg_nsw_link_default[i].param_off; 1348 1349 if (_nscd_cfg_nsw_db[j].name != dbnj) { 1350 for (j = 0; j < _nscd_cfg_num_nsw_db; j++) { 1351 1352 if (strcmp(spc->db, 1353 _nscd_cfg_nsw_db[j].name) != 0) 1354 continue; 1355 1356 dbnj = _nscd_cfg_nsw_db[j].name; 1357 dbj = _nscd_cfg_nsw_db[j].index; 1358 break; 1359 } 1360 } 1361 1362 src = (char *)&nscd_cfg_nsw_db_data_current[dbj] + 1363 spc->group_off + spc->param_off; 1364 datalen = spc->data_len; 1365 1366 (void) memcpy(dest, src, datalen); 1367 } 1368 1369 /* fix up variable length fields */ 1370 for (i = 0; i < _nscd_cfg_num_nsw_db; i++) { 1371 1372 rc = _nscd_cfg_set_vlen_data_int( 1373 &nscd_cfg_nsw_db_data_current[i], 1374 &nscd_cfg_nsw_db_data_current[i], nscd_false); 1375 if (rc != NSCD_SUCCESS) 1376 return (rc); 1377 } 1378 1379 nscd_cfg_nsw_alldb_rwlock = calloc(1, sizeof (rwlock_t)); 1380 if (nscd_cfg_nsw_alldb_rwlock == NULL) 1381 return (NSCD_NO_MEMORY); 1382 1383 (void) rwlock_init(nscd_cfg_nsw_alldb_rwlock, NULL, NULL); 1384 1385 rc = _nscd_cfg_set_vlen_data_int( 1386 &nscd_cfg_nsw_db_data_default, 1387 nscd_cfg_nsw_alldb_current, nscd_false); 1388 if (rc != NSCD_SUCCESS) 1389 return (rc); 1390 1391 /* 1392 * notify and send the configuration data to 1393 * the nscd components 1394 */ 1395 rc = _nscd_cfg_notify_init(errorp); 1396 if (rc != NSCD_SUCCESS) 1397 return (rc); 1398 1399 return (NSCD_SUCCESS); 1400 } 1401 1402 static nscd_rc_t 1403 _nscd_cfg_get_handle_common( 1404 nscd_cfg_list_type_t type, 1405 char *name, 1406 char *nswdb_name, 1407 nscd_cfg_handle_t **handle, 1408 nscd_cfg_error_t **errorp) 1409 { 1410 1411 int i, is_global; 1412 char *desc_str; 1413 nscd_cfg_handle_t *h; 1414 nscd_cfg_param_desc_t *pdesc; 1415 nscd_cfg_stat_desc_t *sdesc; 1416 char *me = "_nscd_cfg_get_handle_common"; 1417 char msg[NSCD_CFG_MAX_ERR_MSG_LEN]; 1418 nscd_rc_t rc = NSCD_INVALID_ARGUMENT; 1419 1420 if (handle == NULL) { 1421 1422 (void) snprintf(msg, sizeof (msg), 1423 gettext("address of handle not specified")); 1424 if (errorp) 1425 *errorp = _nscd_cfg_make_error(rc, msg); 1426 1427 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 1428 (me, "invalid argument: %s\n", msg); 1429 1430 return (rc); 1431 } 1432 1433 *handle = NULL; 1434 1435 if (name == NULL) { 1436 1437 (void) snprintf(msg, sizeof (msg), 1438 gettext("name not specified")); 1439 if (errorp) 1440 *errorp = _nscd_cfg_make_error(rc, msg); 1441 1442 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 1443 (me, "invalid argument: %s\n"); 1444 1445 return (rc); 1446 } 1447 1448 h = calloc(1, sizeof (nscd_cfg_handle_t)); 1449 if (h == NULL) 1450 return (NSCD_NO_MEMORY); 1451 h->type = type; 1452 1453 if (type == NSCD_CFG_LIST_PARAM) 1454 desc_str = gettext("configuration parameter"); 1455 else 1456 desc_str = gettext("statistics"); 1457 1458 /* get param or stat descriptor */ 1459 i = _nscd_cfg_get_index(name, type); 1460 if (i != -1) { 1461 1462 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 1463 (me, "%s: index of %s is %d\n", desc_str, name, i); 1464 1465 if (type == NSCD_CFG_LIST_PARAM) { 1466 pdesc = &_nscd_cfg_param_desc[i]; 1467 (void) memcpy(&h->desc, &pdesc, sizeof (pdesc)); 1468 is_global = _nscd_cfg_flag_is_set( 1469 pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL); 1470 1471 /* hidden params are not exposed */ 1472 if (_nscd_cfg_flag_is_set( 1473 pdesc->pflag, NSCD_CFG_PFLAG_HIDDEN)) 1474 i = -1; 1475 1476 if (_nscd_cfg_flag_is_set(pdesc->pflag, 1477 NSCD_CFG_PFLAG_OBSOLETE)) { 1478 _NSCD_LOG(NSCD_LOG_CONFIG, 1479 NSCD_LOG_LEVEL_WARNING) 1480 (me, 1481 gettext("%s: %s is obsolete and will be ignored\n"), 1482 desc_str, name); 1483 } 1484 } else { 1485 sdesc = &_nscd_cfg_stat_desc[i]; 1486 (void) memcpy(&h->desc, &sdesc, sizeof (sdesc)); 1487 is_global = _nscd_cfg_flag_is_set( 1488 sdesc->sflag, NSCD_CFG_SFLAG_GLOBAL); 1489 } 1490 } 1491 1492 if (i == -1) { 1493 1494 (void) snprintf(msg, sizeof (msg), 1495 gettext("%s: unknown name \"%s\""), desc_str, name); 1496 if (errorp) 1497 *errorp = _nscd_cfg_make_error(rc, msg); 1498 1499 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 1500 (me, "%s\n", msg); 1501 1502 free(h); 1503 return (rc); 1504 } 1505 1506 /* 1507 * if the param/stat is not a global one, we need to 1508 * know which nsswitch database we are dealing with 1509 */ 1510 if (is_global == 0) { 1511 if (nswdb_name == NULL) { 1512 1513 (void) snprintf(msg, sizeof (msg), 1514 gettext("%s: switch database name not specified"), 1515 desc_str); 1516 if (errorp) 1517 *errorp = _nscd_cfg_make_error(rc, msg); 1518 1519 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 1520 (me, "%s for non-global param or stat %s\n", 1521 msg, name); 1522 1523 free(h); 1524 return (rc); 1525 } 1526 } else { 1527 1528 if (nswdb_name != NULL) { 1529 1530 (void) snprintf(msg, sizeof (msg), 1531 gettext("%s: switch database specified for global data"), 1532 desc_str); 1533 if (errorp) 1534 *errorp = _nscd_cfg_make_error(rc, msg); 1535 1536 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 1537 (me, "%s %s\n", msg, name); 1538 1539 free(h); 1540 return (rc); 1541 } 1542 1543 *handle = h; 1544 return (NSCD_SUCCESS); 1545 } 1546 1547 /* get nsw DB id */ 1548 i = _nscd_cfg_get_index(nswdb_name, NSCD_CFG_LIST_NSW_DB); 1549 if (i != -1) { 1550 1551 if (i == NSCD_CFG_NSW_ALLDB_INDEX) 1552 h->nswdb = &_nscd_cfg_nsw_alldb; 1553 else 1554 h->nswdb = &_nscd_cfg_nsw_db[i]; 1555 1556 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 1557 (me, "%s: index of %s is %d\n", 1558 desc_str, nswdb_name, i); 1559 } else { 1560 1561 (void) snprintf(msg, sizeof (msg), 1562 gettext("%s: unknown switch database name \"%s\""), 1563 desc_str, nswdb_name); 1564 if (errorp) 1565 *errorp = _nscd_cfg_make_error(rc, msg); 1566 1567 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 1568 (me, "%s\n", msg); 1569 1570 free(h); 1571 return (NSCD_CFG_UNSUPPORTED_SWITCH_DB); 1572 } 1573 1574 *handle = h; 1575 1576 return (NSCD_SUCCESS); 1577 } 1578 1579 nscd_rc_t 1580 _nscd_cfg_get_handle( 1581 char *param_name, 1582 char *nswdb_name, 1583 nscd_cfg_handle_t **handle, 1584 nscd_cfg_error_t **errorp) 1585 { 1586 1587 return (_nscd_cfg_get_handle_common(NSCD_CFG_LIST_PARAM, 1588 param_name, nswdb_name, handle, errorp)); 1589 } 1590 1591 nscd_rc_t 1592 _nscd_cfg_get_stat_handle( 1593 char *stat_name, 1594 char *nswdb_name, 1595 nscd_cfg_handle_t **handle, 1596 nscd_cfg_error_t **errorp) 1597 { 1598 1599 return (_nscd_cfg_get_handle_common(NSCD_CFG_LIST_STAT, 1600 stat_name, nswdb_name, handle, errorp)); 1601 } 1602 1603 void 1604 _nscd_cfg_free_handle( 1605 nscd_cfg_handle_t *handle) 1606 { 1607 1608 free(handle); 1609 1610 } 1611 1612 static void 1613 _nscd_cfg_free_vlen_data_group( 1614 nscd_cfg_param_desc_t *gdesc, 1615 void *group_data, 1616 nscd_bool_t in) 1617 { 1618 int num; 1619 void *dest, *ptr; 1620 nscd_cfg_param_desc_t *desc; 1621 1622 desc = gdesc; 1623 1624 num = ((nscd_cfg_group_info_t *)group_data)->num_param; 1625 1626 while (num-- > 0) { 1627 1628 desc++; 1629 1630 /* skip fixed length data */ 1631 if (_nscd_cfg_flag_is_not_set(desc->pflag, 1632 NSCD_CFG_PFLAG_VLEN_DATA)) 1633 continue; 1634 1635 dest = (char *)group_data + desc->p_offset; 1636 ptr = *(char **)dest; 1637 if (ptr == NULL) 1638 continue; 1639 if (in == nscd_true) 1640 _nscd_cfg_free_vlen_data_int(ptr); 1641 else 1642 free(ptr); 1643 } 1644 } 1645 1646 void 1647 _nscd_cfg_free_param_data( 1648 void *data) 1649 { 1650 1651 if (data == NULL) 1652 return; 1653 1654 free(data); 1655 } 1656 1657 void 1658 _nscd_cfg_free_group_data( 1659 nscd_cfg_handle_t *handle, 1660 void *data) 1661 { 1662 1663 nscd_cfg_param_desc_t *desc; 1664 nscd_cfg_group_info_t *gi; 1665 1666 if (handle == NULL || data == NULL) 1667 return; 1668 1669 desc = _nscd_cfg_get_desc(handle); 1670 gi = (nscd_cfg_group_info_t *)data; 1671 if (desc->p_fn != gi->num_param) 1672 return; 1673 1674 _nscd_cfg_free_vlen_data_group(desc, data, nscd_false); 1675 1676 free(data); 1677 } 1678 1679 void 1680 _nscd_cfg_free_error( 1681 nscd_cfg_error_t *error) 1682 { 1683 1684 if (error == NULL) 1685 return; 1686 1687 free(error); 1688 } 1689 1690 static nscd_rc_t 1691 _nscd_cfg_copy_param_data( 1692 nscd_cfg_param_desc_t *desc, 1693 void *dest, 1694 void *pdata, 1695 nscd_bool_t in, 1696 nscd_bool_t set_addr) 1697 { 1698 1699 char *me = "_nscd_cfg_copy_param_data"; 1700 void *tmp; 1701 int dlen; 1702 nscd_rc_t rc = NSCD_SUCCESS; 1703 1704 if (desc == NULL || dest == NULL) { 1705 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 1706 (me, "input desc == %p, dest == %p\n", desc, dest); 1707 return (NSCD_INVALID_ARGUMENT); 1708 } 1709 1710 /* fixed length data */ 1711 if (_nscd_cfg_flag_is_not_set(desc->pflag, 1712 NSCD_CFG_PFLAG_VLEN_DATA)) { 1713 (void) memcpy(dest, pdata, desc->p_size); 1714 goto done; 1715 } 1716 1717 1718 /* variable length data from this point on */ 1719 1720 /* make a copy of the variable length data */ 1721 rc = _nscd_cfg_copy_vlen_data(pdata, &tmp, desc, &dlen, in); 1722 if (rc != NSCD_SUCCESS) 1723 goto done; 1724 1725 if (in == nscd_true) { /* data to internal */ 1726 1727 /* free the variable length data in the config store */ 1728 if (*(char **)dest != NULL) 1729 _nscd_cfg_free_vlen_data_int(*(char **)dest); 1730 } 1731 1732 if (set_addr == nscd_true) { 1733 /* 1734 * set the addr of the vlen data 1735 */ 1736 *(char **)dest = tmp; 1737 } else { 1738 /* 1739 * copy the data content (not address) 1740 */ 1741 (void) memcpy(dest, tmp, dlen); 1742 } 1743 1744 done: 1745 1746 return (rc); 1747 } 1748 1749 static nscd_rc_t 1750 _nscd_cfg_copy_group_data_in( 1751 nscd_cfg_param_desc_t *gdesc, 1752 nscd_cfg_group_info_t *gi, 1753 void *group_dest, 1754 void *group_src) 1755 { 1756 int i, num; 1757 nscd_cfg_param_desc_t *desc; 1758 void *src, *dest; 1759 1760 i = 0; 1761 num = gi->num_param; 1762 desc = gdesc; 1763 1764 while (num-- > 0) { 1765 1766 desc++; 1767 1768 /* if member not selected by bitmap, skip */ 1769 if (_nscd_cfg_bitmap_is_not_set(gi->bitmap, i++)) 1770 continue; 1771 1772 src = (char *)group_src + desc->p_offset; 1773 dest = (char *)group_dest + desc->p_offset; 1774 1775 /* 1776 * if variable length data, free and replace the old 1777 * with the new 1778 */ 1779 if (_nscd_cfg_flag_is_set(desc->pflag, 1780 NSCD_CFG_PFLAG_VLEN_DATA)) { 1781 _nscd_cfg_free_vlen_data_int(*(char **)dest); 1782 *(char **)dest = *(char **)src; 1783 *(char **)src = NULL; 1784 } else { 1785 /* 1786 * fixed length data, just copy it 1787 */ 1788 (void) memcpy(dest, src, desc->p_size); 1789 } 1790 } 1791 1792 return (NSCD_SUCCESS); 1793 } 1794 1795 static nscd_rc_t 1796 _nscd_cfg_copy_group_data_out( 1797 nscd_cfg_param_desc_t *gdesc, 1798 void *group_dest, 1799 void *group_src) 1800 { 1801 1802 char *me = "_nscd_cfg_copy_group_data_out"; 1803 void *src, *dest; 1804 int dlen; 1805 int num; 1806 nscd_cfg_group_info_t *gi; 1807 nscd_rc_t rc = NSCD_SUCCESS; 1808 nscd_cfg_param_desc_t *desc; 1809 1810 if (group_dest == NULL) { 1811 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 1812 (me, "input group_dest = NULL\n"); 1813 return (NSCD_INVALID_ARGUMENT); 1814 } 1815 1816 gi = _nscd_cfg_get_gi(group_src); 1817 num = gi->num_param; 1818 desc = gdesc; 1819 1820 while (num-- > 0) { 1821 1822 desc++; 1823 1824 dest = (char *)group_dest + desc->p_offset; 1825 src = (char *)group_src + desc->p_offset; 1826 1827 /* 1828 * if variable length data, get the real 1829 * address and length of the data 1830 */ 1831 if (_nscd_cfg_flag_is_set(desc->pflag, 1832 NSCD_CFG_PFLAG_VLEN_DATA)) { 1833 src = _nscd_cfg_locate_vlen_data(src, &dlen); 1834 if (dlen == NULL) 1835 continue; 1836 } 1837 1838 /* 1839 * The nscd_true asks _nscd_cfg_copy_param_data 1840 * to set addr of the vlen data in 'dest' rather 1841 * than copying the data content 1842 */ 1843 rc = _nscd_cfg_copy_param_data(desc, dest, src, 1844 nscd_false, nscd_true); 1845 if (rc != NSCD_SUCCESS) { 1846 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 1847 (me, "unable to copy param data for %s\n", 1848 desc->id.name); 1849 1850 _nscd_cfg_free_vlen_data_group(gdesc, 1851 group_dest, nscd_false); 1852 1853 free(group_dest); 1854 1855 return (rc); 1856 } 1857 } 1858 1859 /* 1860 * set group bitmap 1861 */ 1862 (void) memcpy(group_dest, group_src, 1863 sizeof (nscd_cfg_group_info_t)); 1864 1865 return (rc); 1866 } 1867 1868 1869 /* 1870 * group_cfg is needed always; group_src may be NULL if 1871 * param_index not zero and pdata not NULL; group_cfg and 1872 * pdata should not be both non-NULL 1873 */ 1874 static nscd_rc_t 1875 _nscd_cfg_copy_group_data_merge( 1876 nscd_cfg_param_desc_t *gdesc, 1877 void **group_dest, 1878 void *group_src, 1879 void *group_cfg, 1880 int param_index, 1881 void *pdata) 1882 { 1883 1884 char *me = "_nscd_cfg_copy_group_data_merge"; 1885 void *src, *dest, *tmp_dest = NULL; 1886 int num, i = 0; 1887 nscd_cfg_group_info_t *gi; 1888 nscd_rc_t rc = NSCD_SUCCESS; 1889 nscd_cfg_param_desc_t *desc; 1890 nscd_cfg_bitmap_t bitmap; 1891 1892 if (group_dest == NULL) { 1893 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 1894 (me, "input **group_dest == NULL\n"); 1895 return (NSCD_INVALID_ARGUMENT); 1896 } 1897 1898 if (group_cfg == NULL) { 1899 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 1900 (me, "input **group_cfg == NULL\n"); 1901 return (NSCD_INVALID_ARGUMENT); 1902 } 1903 1904 if (param_index != NULL && pdata == NULL) { 1905 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 1906 (me, "param_index != NULL but pdata == %p\n", pdata); 1907 return (NSCD_INVALID_ARGUMENT); 1908 } 1909 1910 tmp_dest = calloc(1, gdesc->g_size); 1911 if (tmp_dest == NULL) 1912 return (NSCD_NO_MEMORY); 1913 1914 if (group_src != NULL) 1915 gi = _nscd_cfg_get_gi(group_src); 1916 else { 1917 gi = _nscd_cfg_get_gi(group_cfg); 1918 bitmap = NSCD_CFG_BITMAP_ZERO; 1919 } 1920 1921 num = gi->num_param; 1922 desc = gdesc; 1923 1924 while (num-- > 0) { 1925 1926 desc++; 1927 1928 dest = (char *)tmp_dest + desc->p_offset; 1929 1930 /* 1931 * if member not selected by bitmap in group_src, 1932 * get the member data in group_cfg 1933 */ 1934 if (_nscd_cfg_bitmap_is_not_set(gi->bitmap, i++) || 1935 group_src == NULL) { 1936 src = (char *)group_cfg + desc->p_offset; 1937 } else 1938 src = (char *)group_src + desc->p_offset; 1939 1940 if (desc->id.index == param_index) { 1941 1942 /* use the param data in pdata if provided */ 1943 src = pdata; 1944 _nscd_cfg_bitmap_set_nth(bitmap, i); 1945 } 1946 1947 /* 1948 * if variable length data, get to the data 1949 * instead of pointer to the data 1950 */ 1951 if (_nscd_cfg_flag_is_set(desc->pflag, 1952 NSCD_CFG_PFLAG_VLEN_DATA)) 1953 src = *(char **)src; 1954 1955 /* 1956 * nscd_true asks _nscd_cfg_copy_param_data to 1957 * set addr of the vlen data in 'dest' rather 1958 * than copying the data content 1959 */ 1960 rc = _nscd_cfg_copy_param_data(desc, dest, src, 1961 nscd_true, nscd_true); 1962 if (rc != NSCD_SUCCESS) { 1963 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 1964 (me, "unable to copy param data for %s\n", 1965 desc->id.name); 1966 1967 _nscd_cfg_free_vlen_data_group(gdesc, 1968 tmp_dest, nscd_true); 1969 1970 free(tmp_dest); 1971 1972 return (rc); 1973 } 1974 } 1975 1976 *group_dest = tmp_dest; 1977 1978 /* 1979 * set bitmap: if input is group data, use the one 1980 * given; if input is param data, use the one computed 1981 * above 1982 */ 1983 if (group_src != NULL) 1984 (void) memcpy(*group_dest, group_src, 1985 sizeof (nscd_cfg_group_info_t)); 1986 else { 1987 gi = _nscd_cfg_get_gi(*group_dest); 1988 _nscd_cfg_bitmap_set(&gi->bitmap, bitmap); 1989 } 1990 1991 return (rc); 1992 } 1993 1994 /* ARGSUSED */ 1995 nscd_rc_t 1996 _nscd_cfg_get( 1997 nscd_cfg_handle_t *handle, 1998 void **data, 1999 int *data_len, 2000 nscd_cfg_error_t **errorp) 2001 { 2002 char *me = "_nscd_cfg_get"; 2003 int dlen; 2004 nscd_rc_t rc = NSCD_SUCCESS; 2005 nscd_cfg_id_t *nswdb; 2006 nscd_cfg_param_desc_t *desc; 2007 void *cfg_data, *ptr = NULL; 2008 nscd_bool_t get_group = nscd_false; 2009 nscd_bool_t out = nscd_false; 2010 nscd_cfg_lock_t *lock = NULL; 2011 2012 if (data_len != NULL) 2013 *data_len = 0; 2014 2015 if (data == NULL) { 2016 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2017 (me, "input data = %p\n", data); 2018 return (NSCD_INVALID_ARGUMENT); 2019 } 2020 2021 *data = NULL; 2022 2023 if (handle == NULL) { 2024 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2025 (me, "handle is NULL\n"); 2026 return (NSCD_INVALID_ARGUMENT); 2027 } 2028 2029 nswdb = handle->nswdb; 2030 desc = (nscd_cfg_param_desc_t *)handle->desc; 2031 2032 if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) 2033 get_group = nscd_true; 2034 2035 /* 2036 * locate the current value of the param or group 2037 * and lock the config data for reading 2038 */ 2039 rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_true, desc, 2040 nswdb, get_group, NULL, &dlen, &lock); 2041 if (rc != NSCD_SUCCESS) { 2042 2043 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2044 (me, "unable to locate config data\n"); 2045 return (rc); 2046 2047 } else if (cfg_data == NULL) /* NULL vlen data */ 2048 goto done; 2049 2050 ptr = calloc(1, dlen); 2051 if (ptr == NULL) { 2052 rc = NSCD_NO_MEMORY; 2053 goto error_exit; 2054 } 2055 2056 if (get_group == nscd_true) { 2057 2058 rc = _nscd_cfg_copy_group_data_out(desc, ptr, cfg_data); 2059 if (rc != NSCD_SUCCESS) { 2060 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2061 (me, "unable to copy group data %p: " 2062 "error = %d\n", cfg_data, rc); 2063 2064 goto error_exit; 2065 } 2066 } else { 2067 /* 2068 * nscd_false asks _nscd_cfg_copy_param_data to 2069 * copy the data content rather than just setting 2070 * the addr of the vlen data in 'ptr' 2071 */ 2072 rc = _nscd_cfg_copy_param_data(desc, ptr, cfg_data, 2073 out, nscd_false); 2074 2075 if (rc != NSCD_SUCCESS) { 2076 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2077 (me, "unable to copy param data %p: " 2078 "error = %d\n", cfg_data, rc); 2079 2080 goto error_exit; 2081 } 2082 } 2083 2084 *data = ptr; 2085 2086 done: 2087 2088 if (data_len != NULL) 2089 *data_len = dlen; 2090 2091 _nscd_cfg_unlock(lock); 2092 2093 return (NSCD_SUCCESS); 2094 2095 error_exit: 2096 2097 _nscd_cfg_unlock(lock); 2098 if (ptr != NULL) 2099 free(ptr); 2100 2101 return (rc); 2102 } 2103 2104 /* 2105 * three type of data: 2106 * 1 - single param 2107 * desc is that of the param 2108 * 2 - single param to be sent in a group 2109 * a single bit is set in the bitmap, 2110 * desc is that of the group 2111 * 3 - group data 2112 * one of more bits are set in the bitmap, 2113 * desc is that of the group 2114 */ 2115 static nscd_rc_t 2116 _nscd_cfg_notify_s( 2117 nscd_cfg_param_desc_t *desc, 2118 nscd_cfg_id_t *nswdb, 2119 void *data, 2120 nscd_cfg_error_t **errorp) 2121 { 2122 int i, num, is_group = 0; 2123 void *cookie = NULL; 2124 void *cdata; 2125 nscd_rc_t rc; 2126 nscd_cfg_flag_t dflag, dflag1; 2127 nscd_cfg_bitmap_t bitmap_s, bitmap_in, *bitmap_addr = NULL; 2128 nscd_cfg_group_info_t *gi; 2129 2130 if (errorp != NULL) 2131 *errorp = NULL; 2132 2133 /* 2134 * Set data flag going with data to be sent to the 2135 * verify/notify routines. To allow the config flag 2136 * be exipandable, set the bits one by one. 2137 */ 2138 dflag = NSCD_CFG_FLAG_ZERO; 2139 dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_STATIC_DATA); 2140 if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) { 2141 dflag = _nscd_cfg_flag_set(dflag, NSCD_CFG_DFLAG_GROUP); 2142 is_group = 1; 2143 } 2144 if (nswdb != NULL && 2145 strcmp(NSCD_CFG_NSW_ALLDB, nswdb->name) == 0) 2146 dflag = _nscd_cfg_flag_set(dflag, 2147 NSCD_CFG_DFLAG_SET_ALL_DB); 2148 2149 /* 2150 * the bitmap in the input data may be replaced before 2151 * sending to the components, so save the bitmap for 2152 * later use 2153 */ 2154 if (is_group == 1) { 2155 gi = _nscd_cfg_get_gi(data); 2156 bitmap_in = gi->bitmap; 2157 bitmap_addr = &(gi->bitmap); 2158 2159 if (_nscd_cfg_flag_is_set(desc->pflag, 2160 NSCD_CFG_PFLAG_INIT_SEND_WHOLE_GROUP)) 2161 /* send the entire group just once */ 2162 num = 1; 2163 2164 else { /* send individual members one by one */ 2165 2166 num = desc->p_fn; 2167 2168 /* 2169 * skip the first desc which is for the group 2170 * and get to the desc for the first member 2171 */ 2172 desc++; 2173 2174 dflag = _nscd_cfg_flag_unset(dflag, 2175 NSCD_CFG_DFLAG_GROUP); 2176 } 2177 } else { 2178 /* not group data, send the member once */ 2179 num = 1; 2180 } 2181 2182 dflag1 = dflag; 2183 for (i = 0; i < num; i++, desc++) { 2184 2185 dflag = dflag1; 2186 2187 if (is_group == 0) { 2188 cdata = data; 2189 goto verify_data; 2190 } 2191 2192 if (_nscd_cfg_flag_is_set(desc->pflag, 2193 NSCD_CFG_PFLAG_SEND_BIT_SELECTED)) { 2194 2195 /* set the bitmap to select just this member */ 2196 bitmap_s = NSCD_CFG_BITMAP_ZERO; 2197 _nscd_cfg_bitmap_set_nth(bitmap_s, i); 2198 /* replace the bitmap in the input data */ 2199 _nscd_cfg_bitmap_set(bitmap_addr, bitmap_s); 2200 2201 /* 2202 * send the whole group but with only one 2203 * member selected 2204 */ 2205 cdata = data; 2206 2207 dflag = _nscd_cfg_flag_set(dflag, 2208 NSCD_CFG_DFLAG_GROUP); 2209 dflag = _nscd_cfg_flag_set(dflag, 2210 NSCD_CFG_DFLAG_BIT_SELECTED); 2211 } else { 2212 /* 2213 * send param data or group data: 2214 * param data - non-xero desc->p_offset 2215 * group data - zero desc->p_offset 2216 */ 2217 cdata = (char *)data + desc->p_offset; 2218 2219 /* 2220 * if variable length data, need to send pointer 2221 * to the data (not the address of the pointer) 2222 */ 2223 if (_nscd_cfg_flag_is_set(desc->pflag, 2224 NSCD_CFG_PFLAG_VLEN_DATA)) 2225 cdata = *(char **)cdata; 2226 } 2227 2228 verify_data: 2229 2230 if (desc->verify != NULL) { 2231 dflag = _nscd_cfg_flag_set(dflag, 2232 NSCD_CFG_DFLAG_VERIFY); 2233 rc = desc->verify(cdata, desc, nswdb, 2234 dflag, errorp, &cookie); 2235 if (rc != NSCD_SUCCESS) 2236 goto error_exit; 2237 } 2238 2239 if (desc->notify != NULL) { 2240 dflag = _nscd_cfg_flag_set(dflag, 2241 NSCD_CFG_DFLAG_NOTIFY); 2242 2243 rc = desc->notify(data, desc, nswdb, 2244 dflag, errorp, cookie); 2245 if (rc != NSCD_SUCCESS) 2246 goto error_exit; 2247 } 2248 } 2249 2250 rc = NSCD_SUCCESS; 2251 2252 error_exit: 2253 2254 /* restore the bitmap in the input data */ 2255 if (bitmap_addr != NULL) 2256 _nscd_cfg_bitmap_set(bitmap_addr, bitmap_in); 2257 2258 return (rc); 2259 } 2260 2261 /* 2262 * Convert string 'str' to data based on the data type in 'desc'. 2263 * 'data' points to the buffer in which the converted data 2264 * is placed. '*data_p' points to the buffer, or in the case 2265 * of a string data type, points to the untoched string (i.e., 2266 * 'str'). 2267 */ 2268 nscd_rc_t 2269 _nscd_cfg_str_to_data( 2270 nscd_cfg_param_desc_t *desc, 2271 char *str, 2272 void *data, 2273 void **data_p, 2274 nscd_cfg_error_t **errorp) 2275 { 2276 2277 char *me = "_nscd_cfg_str_to_data"; 2278 char *c; 2279 nscd_cfg_bitmap_t bitmap; 2280 char msg[NSCD_CFG_MAX_ERR_MSG_LEN]; 2281 nscd_rc_t rc = NSCD_CFG_DATA_CONVERSION_FAILED; 2282 2283 if (desc == NULL || str == NULL || data == NULL) { 2284 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2285 (me, "ERROR: one of the following is NULL " 2286 "desc = %p, str = %p, data = %p, data_p = %p\n", 2287 desc, str, data, data_p); 2288 2289 return (NSCD_INVALID_ARGUMENT); 2290 } 2291 *data_p = data; 2292 2293 /* if description is that of a group, return error */ 2294 if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) { 2295 2296 (void) snprintf(msg, sizeof (msg), 2297 gettext("single data specified for group %s"), desc->id.name); 2298 2299 if (errorp != NULL) 2300 *errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT, 2301 msg); 2302 2303 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2304 (me, "ERROR: %s)\n", msg); 2305 2306 return (NSCD_INVALID_ARGUMENT); 2307 2308 } 2309 2310 if (desc->type == NSCD_CFG_DATA_STRING) { 2311 if (strcmp(str, NSCD_NULL) == 0) 2312 *(char **)data_p = NULL; 2313 else { 2314 /* remove the " char if quoted string */ 2315 if (str[0] == '"') { 2316 c = str + strlen(str) - 1; 2317 if (*c == '"') 2318 *c = '\0'; 2319 *(char **)data_p = str + 1; 2320 } else 2321 *(char **)data_p = str; 2322 2323 } 2324 return (NSCD_SUCCESS); 2325 } 2326 2327 if (str == NULL) { 2328 2329 (void) snprintf(msg, sizeof (msg), 2330 gettext("data must be specified for %s"), desc->id.name); 2331 2332 if (errorp != NULL) 2333 *errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT, 2334 msg); 2335 2336 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2337 (me, "ERROR: %s\n", msg); 2338 2339 return (NSCD_INVALID_ARGUMENT); 2340 2341 } 2342 2343 switch (desc->type) { 2344 2345 case NSCD_CFG_DATA_BOOLEAN: 2346 2347 if (strcasecmp(str, "yes") == 0) 2348 *(nscd_bool_t *)data = nscd_true; 2349 else if (strcasecmp(str, "no") == 0) 2350 *(nscd_bool_t *)data = nscd_false; 2351 else { 2352 2353 (void) snprintf(msg, sizeof (msg), 2354 gettext("data (%s) must be 'yes' or 'no' for %s"), 2355 str, desc->id.name); 2356 2357 if (errorp != NULL) 2358 *errorp = _nscd_cfg_make_error(NSCD_INVALID_ARGUMENT, 2359 msg); 2360 2361 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2362 (me, "ERROR: %s\n", msg); 2363 2364 return (NSCD_INVALID_ARGUMENT); 2365 } 2366 2367 break; 2368 2369 case NSCD_CFG_DATA_INTEGER: 2370 2371 errno = 0; 2372 *(int *)data = (int)strtol(str, (char **)NULL, 10); 2373 if (errno != NULL) { 2374 2375 (void) snprintf(msg, sizeof (msg), 2376 gettext("unable to convert data (%s) for %s"), 2377 str, desc->id.name); 2378 2379 if (errorp != NULL) 2380 *errorp = _nscd_cfg_make_error(rc, msg); 2381 2382 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2383 (me, "ERROR: %s\n", msg); 2384 2385 return (rc); 2386 } 2387 2388 break; 2389 2390 case NSCD_CFG_DATA_BITMAP: 2391 2392 errno = 0; 2393 bitmap = (nscd_cfg_bitmap_t)strtol(str, (char **)NULL, 10); 2394 if (errno != NULL) { 2395 2396 (void) snprintf(msg, sizeof (msg), 2397 gettext("unable to convert data (%s) for %s"), 2398 str, desc->id.name); 2399 2400 if (errorp != NULL) 2401 *errorp = _nscd_cfg_make_error(rc, msg); 2402 2403 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2404 (me, "ERROR: %s\n", msg); 2405 2406 return (rc); 2407 } 2408 2409 _nscd_cfg_bitmap_set(data, bitmap); 2410 2411 break; 2412 2413 } 2414 2415 return (NSCD_SUCCESS); 2416 } 2417 2418 2419 nscd_rc_t 2420 _nscd_cfg_set( 2421 nscd_cfg_handle_t *handle, 2422 void *data, 2423 nscd_cfg_error_t **errorp) 2424 { 2425 char *me = "_nscd_cfg_set"; 2426 int dlen; 2427 nscd_cfg_id_t *nswdb; 2428 nscd_cfg_param_desc_t *desc, *gdesc; 2429 nscd_cfg_group_info_t *gi; 2430 char *nswdb_name, *param_name; 2431 void *pdata = NULL; 2432 void *cfg_data, *vdata_addr = NULL; 2433 nscd_bool_t get_group = 0; 2434 nscd_bool_t in = nscd_true; 2435 nscd_cfg_lock_t *lock = NULL; 2436 nscd_rc_t rc = NSCD_SUCCESS; 2437 2438 if (handle == NULL) { 2439 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2440 (me, "handle is NULL\n"); 2441 return (NSCD_INVALID_ARGUMENT); 2442 } 2443 2444 nswdb = handle->nswdb; 2445 desc = (nscd_cfg_param_desc_t *)handle->desc; 2446 if (nswdb == NULL) 2447 nswdb_name = "global"; 2448 else 2449 nswdb_name = nswdb->name; 2450 param_name = desc->id.name; 2451 2452 if (data == NULL && _nscd_cfg_flag_is_not_set(desc->pflag, 2453 NSCD_CFG_PFLAG_VLEN_DATA)) { 2454 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2455 (me, "data == NULL\n"); 2456 return (NSCD_INVALID_ARGUMENT); 2457 } 2458 2459 if (_nscd_cfg_flag_is_set(desc->pflag, 2460 NSCD_CFG_PFLAG_UPDATE_SEND_WHOLE_GROUP) || 2461 _nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP)) 2462 get_group = nscd_true; 2463 2464 /* 2465 * locate the current value of the param or group 2466 * and lock the config data for writing 2467 */ 2468 rc = _nscd_cfg_locate_cfg_data(&cfg_data, nscd_false, desc, 2469 nswdb, get_group, &vdata_addr, &dlen, &lock); 2470 if (rc != NSCD_SUCCESS) { 2471 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2472 (me, "unable to locate config data (rc = %d)\n", rc); 2473 return (rc); 2474 } 2475 2476 if (_nscd_cfg_flag_is_set(desc->pflag, NSCD_CFG_PFLAG_GROUP) && 2477 ((nscd_cfg_group_info_t *)cfg_data)->num_param != 2478 ((nscd_cfg_group_info_t *)data)->num_param) { 2479 2480 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2481 (me, "number of parameters in group <%s : %s> not equal: " 2482 "%d in input data, should be %d\n", 2483 NSCD_STR_OR_GLOBAL(nswdb_name), 2484 NSCD_STR_OR_NULL(param_name), 2485 ((nscd_cfg_group_info_t *)data)->num_param, 2486 ((nscd_cfg_group_info_t *)cfg_data)->num_param); 2487 2488 rc = NSCD_INVALID_ARGUMENT; 2489 goto error_exit; 2490 } 2491 2492 /* 2493 * if variable length data, we want the address 2494 * of the pointer pointing to the data 2495 */ 2496 if (vdata_addr != NULL) 2497 cfg_data = vdata_addr; 2498 2499 /* 2500 * just copy in the specified data, if no need 2501 * to verify the data or notify the associated 2502 * component 2503 */ 2504 if (get_group == nscd_true) { 2505 2506 gdesc = &_nscd_cfg_param_desc[desc->g_index]; 2507 2508 rc = _nscd_cfg_copy_group_data_merge( 2509 gdesc, &pdata, data, cfg_data, 2510 desc->id.index, data); 2511 2512 if (rc != NSCD_SUCCESS) { 2513 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2514 (me, "unable to copy group data <%s : %s>\n", 2515 NSCD_STR_OR_GLOBAL(nswdb_name), 2516 NSCD_STR_OR_NULL(param_name)); 2517 2518 goto error_exit; 2519 } 2520 2521 rc = _nscd_cfg_notify_s(gdesc, nswdb, 2522 pdata, errorp); 2523 2524 } else 2525 rc = _nscd_cfg_notify_s(desc, nswdb, data, 2526 errorp); 2527 2528 if (rc != NSCD_SUCCESS) { 2529 2530 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2531 (me, "verifying/notifying of new configuration " 2532 "parameter <%s : %s> failed. %s\n", 2533 NSCD_STR_OR_GLOBAL(nswdb_name), 2534 param_name, (*errorp && (*errorp)->msg) ? 2535 (*errorp)->msg : ""); 2536 2537 goto error_exit; 2538 } 2539 2540 /* 2541 * Move the new config into the config store 2542 */ 2543 rc = NSCD_CFG_SET_PARAM_FAILED; 2544 if (_nscd_cfg_flag_is_set(desc->pflag, 2545 NSCD_CFG_PFLAG_GROUP)) { 2546 gi = _nscd_cfg_get_gi(pdata); 2547 rc = _nscd_cfg_copy_group_data_in(gdesc, gi, 2548 cfg_data, pdata); 2549 } else { 2550 /* 2551 * nscd_true asks _nscd_cfg_copy_param_data to 2552 * set addr of the vlen data in 'cfg_data' rather 2553 * than copying the data content 2554 */ 2555 if (pdata != NULL) 2556 _nscd_cfg_free_vlen_data_group(gdesc, 2557 pdata, in); 2558 2559 rc = _nscd_cfg_copy_param_data(desc, 2560 cfg_data, data, in, nscd_true); 2561 } 2562 2563 if (rc != NSCD_SUCCESS) { 2564 2565 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2566 (me, "unable to make new param data <%s : %s> current\n", 2567 NSCD_STR_OR_GLOBAL(nswdb_name), 2568 NSCD_STR_OR_NULL(param_name)); 2569 } 2570 2571 error_exit: 2572 2573 _nscd_cfg_unlock(lock); 2574 2575 return (rc); 2576 } 2577 2578 nscd_rc_t 2579 _nscd_cfg_set_linked( 2580 nscd_cfg_handle_t *handle, 2581 void *data, 2582 nscd_cfg_error_t **errorp) 2583 { 2584 char *me = "_nscd_cfg_set_linked"; 2585 nscd_cfg_id_t *nswdb; 2586 nscd_cfg_handle_t *hl; 2587 nscd_cfg_param_desc_t *desc; 2588 char *nswdb_name, *param_name, *dbl; 2589 nscd_rc_t rc = NSCD_SUCCESS; 2590 nscd_cfg_nsw_spc_default_t *spc; 2591 int i; 2592 char msg[NSCD_CFG_MAX_ERR_MSG_LEN]; 2593 2594 if (handle == NULL) { 2595 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2596 (me, "handle is NULL\n"); 2597 return (NSCD_INVALID_ARGUMENT); 2598 } 2599 2600 nswdb = handle->nswdb; 2601 desc = (nscd_cfg_param_desc_t *)handle->desc; 2602 2603 /* 2604 * no need to do the special linking thing, 2605 * if a global param, or a group, or not a linked param 2606 */ 2607 if (nswdb == NULL || _nscd_cfg_flag_is_set(desc->pflag, 2608 NSCD_CFG_PFLAG_GROUP) || 2609 _nscd_cfg_flag_is_not_set(desc->pflag, 2610 NSCD_CFG_PFLAG_LINKED)) 2611 return (_nscd_cfg_set(handle, data, errorp)); 2612 else 2613 nswdb_name = nswdb->name; 2614 param_name = desc->id.name; 2615 2616 /* 2617 * if a param is linked to another, it can not be 2618 * changed directly 2619 */ 2620 for (i = 0; i < _nscd_cfg_num_link_default; i++) { 2621 2622 if (_nscd_cfg_nsw_link_default[i].data == NULL) 2623 continue; 2624 2625 if (strcmp(_nscd_cfg_nsw_link_default[i].db, 2626 nswdb_name) == 0 && 2627 _nscd_cfg_nsw_link_default[i].group_off == 2628 desc->g_offset && 2629 _nscd_cfg_nsw_link_default[i].param_off == 2630 desc->p_offset) { 2631 2632 rc = NSCD_CFG_READ_ONLY; 2633 2634 (void) snprintf(msg, sizeof (msg), 2635 gettext("vaule of \'%s\' not changeable, change that of \'%s\' instead"), 2636 nswdb->name, "passwd"); 2637 2638 if (errorp != NULL) 2639 *errorp = _nscd_cfg_make_error(rc, msg); 2640 2641 _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR) 2642 (me, "ERROR: %s\n", msg); 2643 2644 return (rc); 2645 } 2646 } 2647 2648 /* 2649 * if a param is linked from another, it should be verify 2650 * and changed first 2651 */ 2652 for (i = 0; i < _nscd_cfg_num_link_default; i++) { 2653 2654 if (_nscd_cfg_nsw_link_default[i].data == NULL) 2655 continue; 2656 2657 spc = _nscd_cfg_nsw_link_default[i].data; 2658 2659 if (strcmp(spc->db, nswdb_name) == 0 && 2660 spc->group_off == desc->g_offset && 2661 spc->param_off == desc->p_offset) { 2662 2663 rc = _nscd_cfg_set(handle, data, errorp); 2664 if (rc != NSCD_SUCCESS) 2665 return (rc); 2666 break; 2667 } 2668 } 2669 2670 /* 2671 * then change all those linked to the one that has been changed 2672 */ 2673 for (i = 0; i < _nscd_cfg_num_link_default; i++) { 2674 2675 if (_nscd_cfg_nsw_link_default[i].data == NULL) 2676 continue; 2677 2678 spc = _nscd_cfg_nsw_link_default[i].data; 2679 2680 if (strcmp(spc->db, nswdb_name) == 0 && 2681 spc->group_off == desc->g_offset && 2682 spc->param_off == desc->p_offset && 2683 _nscd_cfg_nsw_link_default[i].group_off == 2684 desc->g_offset && 2685 _nscd_cfg_nsw_link_default[i].param_off == 2686 desc->p_offset) { 2687 2688 dbl = _nscd_cfg_nsw_link_default[i].db; 2689 2690 rc = _nscd_cfg_get_handle(param_name, dbl, 2691 &hl, errorp); 2692 if (rc != NSCD_SUCCESS) 2693 return (rc); 2694 rc = _nscd_cfg_set(hl, data, errorp); 2695 _nscd_cfg_free_handle(hl); 2696 if (rc != NSCD_SUCCESS) 2697 return (rc); 2698 } 2699 } 2700 2701 return (_nscd_cfg_set(handle, data, errorp)); 2702 } 2703 2704 /* 2705 * Return a list of space-separated database names that 2706 * have at least one of the input sources appeared in the 2707 * configured nsswitch policy string of the databases. 2708 * The return string should be freed by the caller. 2709 * 2710 * For compat sources (compat_group and compat_passwd), 2711 * "group" will be returned, if the policy string for 2712 * compat_group contains one of the input sources. Same 2713 * for compat_passwd and passwd. 2714 */ 2715 char * 2716 _nscd_srcs_in_db_nsw_policy( 2717 int num_src, 2718 char **srcs) 2719 { 2720 uint8_t i, j, n = 0, nc = 0; 2721 uint8_t compat_grp = 0, compat_pwd = 0; 2722 uint8_t *db; 2723 uint8_t *db_compat; 2724 int dlen = 0; 2725 nscd_cfg_nsw_db_data_t *dbcfg; 2726 nscd_cfg_switch_t *sw; 2727 char *outstr = NULL; 2728 char *dbname; 2729 2730 db = (uint8_t *)calloc(_nscd_cfg_num_nsw_db, sizeof (uint8_t)); 2731 if (db == NULL) 2732 return (NULL); 2733 2734 db_compat = (uint8_t *)calloc(_nscd_cfg_num_nsw_db, 2735 sizeof (uint8_t)); 2736 if (db_compat == NULL) { 2737 free(db); 2738 return (NULL); 2739 } 2740 2741 for (i = 0; i < _nscd_cfg_num_nsw_db; i++) { 2742 2743 (void) rw_rdlock(&nscd_cfg_nsw_db_data_rwlock[i]); 2744 2745 dbcfg = &nscd_cfg_nsw_db_data_current[i]; 2746 sw = &dbcfg->sw; 2747 if (sw->nsw_config_string == NULL) 2748 continue; 2749 2750 dbname = _nscd_cfg_nsw_db[i].name; 2751 for (j = 0; j < num_src; j++) { 2752 if (strstr(sw->nsw_config_string, srcs[j]) != 2753 NULL) { 2754 db[n++] = i; 2755 dlen += strlen(dbname) + 1; 2756 } else if (strcmp(sw->nsw_config_string, 2757 "compat") == 0) { 2758 if (strcmp(dbname, "passwd") == 0) { 2759 compat_pwd = 1; 2760 dlen += 7; 2761 } else if (strcmp(dbname, "group") == 0) { 2762 compat_grp = 1; 2763 dlen += 6; 2764 } else { 2765 db_compat[nc++] = i; 2766 dlen += strlen(dbname) + 1; 2767 2768 } 2769 } 2770 } 2771 (void) rw_unlock(&nscd_cfg_nsw_db_data_rwlock[i]); 2772 } 2773 2774 if (dlen != NULL) 2775 outstr = (char *)calloc(1, dlen); 2776 if (outstr == NULL) { 2777 free(db_compat); 2778 free(db); 2779 return (NULL); 2780 } 2781 2782 for (j = 0; j < n; j++) { 2783 dbname = _nscd_cfg_nsw_db[db[j]].name; 2784 if (strstr(dbname, "group_compat") != NULL) { 2785 if (compat_grp == 1) 2786 dbname = "group"; 2787 else 2788 continue; 2789 } else if (strstr(dbname, "passwd_compat") != NULL) { 2790 if (compat_pwd == 1) 2791 dbname = "passwd"; 2792 else 2793 continue; 2794 } 2795 2796 (void) strlcat(outstr, dbname, dlen); 2797 (void) strlcat(outstr, ",", dlen); 2798 } 2799 2800 for (j = 0; j < nc; j++) { 2801 dbname = _nscd_cfg_nsw_db[db_compat[j]].name; 2802 if (compat_pwd == 1) { 2803 (void) strlcat(outstr, dbname, dlen); 2804 (void) strlcat(outstr, " ", dlen); 2805 } 2806 } 2807 2808 free(db); 2809 free(db_compat); 2810 return (outstr); 2811 2812 } 2813