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