1101209Srwatson/*- 2126218Srwatson * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 3101209Srwatson * All rights reserved. 4101209Srwatson * 5101209Srwatson * Redistribution and use in source and binary forms, with or without 6101209Srwatson * modification, are permitted provided that the following conditions 7101209Srwatson * are met: 8101209Srwatson * 1. Redistributions of source code must retain the above copyright 9101209Srwatson * notice, this list of conditions and the following disclaimer. 10101209Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11101209Srwatson * notice, this list of conditions and the following disclaimer in the 12101209Srwatson * documentation and/or other materials provided with the distribution. 13101209Srwatson * 14101209Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15101209Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16101209Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17101209Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18101209Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19101209Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20101209Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21101209Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22101209Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23101209Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24101209Srwatson * SUCH DAMAGE. 25101209Srwatson * 26101209Srwatson */ 27101209Srwatson 28101209Srwatson#include <sys/cdefs.h> 29101209Srwatson__FBSDID("$FreeBSD: releng/11.0/usr.sbin/nscd/config.c 238094 2012-07-04 09:02:12Z se $"); 30101209Srwatson 31140343Scharnier#include <sys/stat.h> 32140343Scharnier#include <sys/time.h> 33140343Scharnier 34140343Scharnier#include <assert.h> 35101209Srwatson#include <math.h> 36101209Srwatson#include <nsswitch.h> 37157986Sdwmalone#include <pthread.h> 38101209Srwatson#include <stdio.h> 39101209Srwatson#include <stdlib.h> 40101209Srwatson#include <string.h> 41101209Srwatson 42101209Srwatson#include "config.h" 43140343Scharnier#include "debug.h" 44101209Srwatson#include "log.h" 45101209Srwatson 46101209Srwatson/* 47101209Srwatson * Default entries, which always exist in the configuration 48101209Srwatson */ 49140343Scharnierconst char *c_default_entries[6] = { 50140343Scharnier NSDB_PASSWD, 51140343Scharnier NSDB_GROUP, 52140343Scharnier NSDB_HOSTS, 53140343Scharnier NSDB_SERVICES, 54140343Scharnier NSDB_PROTOCOLS, 55101209Srwatson NSDB_RPC 56101209Srwatson }; 57101209Srwatson 58101209Srwatsonstatic int configuration_entry_cmp(const void *, const void *); 59140343Scharnierstatic int configuration_entry_sort_cmp(const void *, const void *); 60126218Srwatsonstatic int configuration_entry_cache_mp_sort_cmp(const void *, const void *); 61126218Srwatsonstatic int configuration_entry_cache_mp_cmp(const void *, const void *); 62140343Scharnierstatic int configuration_entry_cache_mp_part_cmp(const void *, const void *); 63140343Scharnierstatic struct configuration_entry *create_configuration_entry(const char *, 64101209Srwatson struct timeval const *, struct timeval const *, 65101209Srwatson struct common_cache_entry_params const *, 66140343Scharnier struct common_cache_entry_params const *, 67101209Srwatson struct mp_cache_entry_params const *); 68140343Scharnier 69101209Srwatsonstatic int 70101209Srwatsonconfiguration_entry_sort_cmp(const void *e1, const void *e2) 71101209Srwatson{ 72126218Srwatson return (strcmp((*((struct configuration_entry **)e1))->name, 73126218Srwatson (*((struct configuration_entry **)e2))->name 74186480Srwatson )); 75126218Srwatson} 76126218Srwatson 77126218Srwatsonstatic int 78126218Srwatsonconfiguration_entry_cmp(const void *e1, const void *e2) 79126218Srwatson{ 80140343Scharnier return (strcmp((const char *)e1, 81126218Srwatson (*((struct configuration_entry **)e2))->name 82126218Srwatson )); 83126218Srwatson} 84126218Srwatson 85126218Srwatsonstatic int 86140343Scharnierconfiguration_entry_cache_mp_sort_cmp(const void *e1, const void *e2) 87126218Srwatson{ 88126218Srwatson return (strcmp((*((cache_entry *)e1))->params->entry_name, 89186480Srwatson (*((cache_entry *)e2))->params->entry_name 90186480Srwatson )); 91186480Srwatson} 92186480Srwatson 93126218Srwatsonstatic int 94126218Srwatsonconfiguration_entry_cache_mp_cmp(const void *e1, const void *e2) 95126218Srwatson{ 96101209Srwatson return (strcmp((const char *)e1, 97101209Srwatson (*((cache_entry *)e2))->params->entry_name 98101209Srwatson )); 99101209Srwatson} 100101209Srwatson 101101209Srwatsonstatic int 102101209Srwatsonconfiguration_entry_cache_mp_part_cmp(const void *e1, const void *e2) 103101209Srwatson{ 104140343Scharnier return (strncmp((const char *)e1, 105140343Scharnier (*((cache_entry *)e2))->params->entry_name, 106140343Scharnier strlen((const char *)e1) 107101209Srwatson )); 108101209Srwatson} 109101209Srwatson 110140343Scharnierstatic struct configuration_entry * 111140343Scharniercreate_configuration_entry(const char *name, 112101209Srwatson struct timeval const *common_timeout, 113101209Srwatson struct timeval const *mp_timeout, 114101209Srwatson struct common_cache_entry_params const *positive_params, 115148240Savatar struct common_cache_entry_params const *negative_params, 116101209Srwatson struct mp_cache_entry_params const *mp_params) 117101209Srwatson{ 118101209Srwatson struct configuration_entry *retval; 119101209Srwatson size_t size; 120101209Srwatson int res; 121140343Scharnier 122101209Srwatson TRACE_IN(create_configuration_entry); 123101209Srwatson assert(name != NULL); 124101209Srwatson assert(positive_params != NULL); 125101209Srwatson assert(negative_params != NULL); 126101209Srwatson assert(mp_params != NULL); 127101209Srwatson 128140343Scharnier retval = calloc(1, 129101209Srwatson sizeof(*retval)); 130101209Srwatson assert(retval != NULL); 131101209Srwatson 132101209Srwatson res = pthread_mutex_init(&retval->positive_cache_lock, NULL); 133101209Srwatson if (res != 0) { 134101209Srwatson free(retval); 135101209Srwatson LOG_ERR_2("create_configuration_entry", 136101209Srwatson "can't create positive cache lock"); 137101209Srwatson TRACE_OUT(create_configuration_entry); 138101209Srwatson return (NULL); 139101209Srwatson } 140101209Srwatson 141101209Srwatson res = pthread_mutex_init(&retval->negative_cache_lock, NULL); 142101209Srwatson if (res != 0) { 143101209Srwatson pthread_mutex_destroy(&retval->positive_cache_lock); 144101209Srwatson free(retval); 145101209Srwatson LOG_ERR_2("create_configuration_entry", 146101209Srwatson "can't create negative cache lock"); 147101209Srwatson TRACE_OUT(create_configuration_entry); 148101209Srwatson return (NULL); 149101209Srwatson } 150101209Srwatson 151101209Srwatson res = pthread_mutex_init(&retval->mp_cache_lock, NULL); 152101209Srwatson if (res != 0) { 153101209Srwatson pthread_mutex_destroy(&retval->positive_cache_lock); 154101209Srwatson pthread_mutex_destroy(&retval->negative_cache_lock); 155101209Srwatson free(retval); 156101209Srwatson LOG_ERR_2("create_configuration_entry", 157140343Scharnier "can't create negative cache lock"); 158101209Srwatson TRACE_OUT(create_configuration_entry); 159101209Srwatson return (NULL); 160101209Srwatson } 161101209Srwatson 162101209Srwatson memcpy(&retval->positive_cache_params, positive_params, 163140343Scharnier sizeof(struct common_cache_entry_params)); 164101209Srwatson memcpy(&retval->negative_cache_params, negative_params, 165101209Srwatson sizeof(struct common_cache_entry_params)); 166101209Srwatson memcpy(&retval->mp_cache_params, mp_params, 167101209Srwatson sizeof(struct mp_cache_entry_params)); 168101209Srwatson 169101209Srwatson size = strlen(name); 170101209Srwatson retval->name = calloc(1, size + 1); 171101209Srwatson assert(retval->name != NULL); 172101209Srwatson memcpy(retval->name, name, size); 173101209Srwatson 174101209Srwatson memcpy(&retval->common_query_timeout, common_timeout, 175101209Srwatson sizeof(struct timeval)); 176101209Srwatson memcpy(&retval->mp_query_timeout, mp_timeout, 177101209Srwatson sizeof(struct timeval)); 178101209Srwatson 179101209Srwatson asprintf(&retval->positive_cache_params.cep.entry_name, "%s+", name); 180101209Srwatson assert(retval->positive_cache_params.cep.entry_name != NULL); 181101209Srwatson 182101209Srwatson asprintf(&retval->negative_cache_params.cep.entry_name, "%s-", name); 183101209Srwatson assert(retval->negative_cache_params.cep.entry_name != NULL); 184101209Srwatson 185101209Srwatson asprintf(&retval->mp_cache_params.cep.entry_name, "%s*", name); 186101209Srwatson assert(retval->mp_cache_params.cep.entry_name != NULL); 187101209Srwatson 188101209Srwatson TRACE_OUT(create_configuration_entry); 189101209Srwatson return (retval); 190140343Scharnier} 191101209Srwatson 192101209Srwatson/* 193101209Srwatson * Creates configuration entry and fills it with default values 194101209Srwatson */ 195101209Srwatsonstruct configuration_entry * 196101209Srwatsoncreate_def_configuration_entry(const char *name) 197101209Srwatson{ 198101209Srwatson struct common_cache_entry_params positive_params, negative_params; 199101209Srwatson struct mp_cache_entry_params mp_params; 200126218Srwatson struct timeval default_common_timeout, default_mp_timeout; 201126218Srwatson 202126218Srwatson struct configuration_entry *res = NULL; 203101209Srwatson 204101209Srwatson TRACE_IN(create_def_configuration_entry); 205101209Srwatson memset(&positive_params, 0, 206101209Srwatson sizeof(struct common_cache_entry_params)); 207101209Srwatson positive_params.cep.entry_type = CET_COMMON; 208101209Srwatson positive_params.cache_entries_size = DEFAULT_CACHE_HT_SIZE; 209101209Srwatson positive_params.max_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE; 210101209Srwatson positive_params.satisf_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE / 2; 211101209Srwatson positive_params.max_lifetime.tv_sec = DEFAULT_POSITIVE_LIFETIME; 212101209Srwatson positive_params.confidence_threshold = DEFAULT_POSITIVE_CONF_THRESH; 213101209Srwatson positive_params.policy = CPT_LRU; 214101209Srwatson 215 memcpy(&negative_params, &positive_params, 216 sizeof(struct common_cache_entry_params)); 217 negative_params.max_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE; 218 negative_params.satisf_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE / 2; 219 negative_params.max_lifetime.tv_sec = DEFAULT_NEGATIVE_LIFETIME; 220 negative_params.confidence_threshold = DEFAULT_NEGATIVE_CONF_THRESH; 221 negative_params.policy = CPT_FIFO; 222 223 memset(&default_common_timeout, 0, sizeof(struct timeval)); 224 default_common_timeout.tv_sec = DEFAULT_COMMON_ENTRY_TIMEOUT; 225 226 memset(&default_mp_timeout, 0, sizeof(struct timeval)); 227 default_mp_timeout.tv_sec = DEFAULT_MP_ENTRY_TIMEOUT; 228 229 memset(&mp_params, 0, 230 sizeof(struct mp_cache_entry_params)); 231 mp_params.cep.entry_type = CET_MULTIPART; 232 mp_params.max_elemsize = DEFAULT_MULTIPART_ELEMENTS_SIZE; 233 mp_params.max_sessions = DEFAULT_MULITPART_SESSIONS_SIZE; 234 mp_params.max_lifetime.tv_sec = DEFAULT_MULITPART_LIFETIME; 235 236 res = create_configuration_entry(name, &default_common_timeout, 237 &default_mp_timeout, &positive_params, &negative_params, 238 &mp_params); 239 240 TRACE_OUT(create_def_configuration_entry); 241 return (res); 242} 243 244void 245destroy_configuration_entry(struct configuration_entry *entry) 246{ 247 TRACE_IN(destroy_configuration_entry); 248 assert(entry != NULL); 249 pthread_mutex_destroy(&entry->positive_cache_lock); 250 pthread_mutex_destroy(&entry->negative_cache_lock); 251 pthread_mutex_destroy(&entry->mp_cache_lock); 252 free(entry->name); 253 free(entry->positive_cache_params.cep.entry_name); 254 free(entry->negative_cache_params.cep.entry_name); 255 free(entry->mp_cache_params.cep.entry_name); 256 free(entry->mp_cache_entries); 257 free(entry); 258 TRACE_OUT(destroy_configuration_entry); 259} 260 261int 262add_configuration_entry(struct configuration *config, 263 struct configuration_entry *entry) 264{ 265 TRACE_IN(add_configuration_entry); 266 assert(entry != NULL); 267 assert(entry->name != NULL); 268 if (configuration_find_entry(config, entry->name) != NULL) { 269 TRACE_OUT(add_configuration_entry); 270 return (-1); 271 } 272 273 if (config->entries_size == config->entries_capacity) { 274 struct configuration_entry **new_entries; 275 276 config->entries_capacity *= 2; 277 new_entries = calloc(1, 278 sizeof(*new_entries) * 279 config->entries_capacity); 280 assert(new_entries != NULL); 281 memcpy(new_entries, config->entries, 282 sizeof(struct configuration_entry *) * 283 config->entries_size); 284 285 free(config->entries); 286 config->entries = new_entries; 287 } 288 289 config->entries[config->entries_size++] = entry; 290 qsort(config->entries, config->entries_size, 291 sizeof(struct configuration_entry *), 292 configuration_entry_sort_cmp); 293 294 TRACE_OUT(add_configuration_entry); 295 return (0); 296} 297 298size_t 299configuration_get_entries_size(struct configuration *config) 300{ 301 TRACE_IN(configuration_get_entries_size); 302 assert(config != NULL); 303 TRACE_OUT(configuration_get_entries_size); 304 return (config->entries_size); 305} 306 307struct configuration_entry * 308configuration_get_entry(struct configuration *config, size_t index) 309{ 310 TRACE_IN(configuration_get_entry); 311 assert(config != NULL); 312 assert(index < config->entries_size); 313 TRACE_OUT(configuration_get_entry); 314 return (config->entries[index]); 315} 316 317struct configuration_entry * 318configuration_find_entry(struct configuration *config, 319 const char *name) 320{ 321 struct configuration_entry **retval; 322 323 TRACE_IN(configuration_find_entry); 324 325 retval = bsearch(name, config->entries, config->entries_size, 326 sizeof(struct configuration_entry *), configuration_entry_cmp); 327 TRACE_OUT(configuration_find_entry); 328 329 return ((retval != NULL) ? *retval : NULL); 330} 331 332/* 333 * All multipart cache entries are stored in the configuration_entry in the 334 * sorted array (sorted by names). The 3 functions below manage this array. 335 */ 336 337int 338configuration_entry_add_mp_cache_entry(struct configuration_entry *config_entry, 339 cache_entry c_entry) 340{ 341 cache_entry *new_mp_entries, *old_mp_entries; 342 343 TRACE_IN(configuration_entry_add_mp_cache_entry); 344 ++config_entry->mp_cache_entries_size; 345 new_mp_entries = malloc(sizeof(*new_mp_entries) * 346 config_entry->mp_cache_entries_size); 347 assert(new_mp_entries != NULL); 348 new_mp_entries[0] = c_entry; 349 350 if (config_entry->mp_cache_entries_size - 1 > 0) { 351 memcpy(new_mp_entries + 1, 352 config_entry->mp_cache_entries, 353 (config_entry->mp_cache_entries_size - 1) * 354 sizeof(cache_entry)); 355 } 356 357 old_mp_entries = config_entry->mp_cache_entries; 358 config_entry->mp_cache_entries = new_mp_entries; 359 free(old_mp_entries); 360 361 qsort(config_entry->mp_cache_entries, 362 config_entry->mp_cache_entries_size, 363 sizeof(cache_entry), 364 configuration_entry_cache_mp_sort_cmp); 365 366 TRACE_OUT(configuration_entry_add_mp_cache_entry); 367 return (0); 368} 369 370cache_entry 371configuration_entry_find_mp_cache_entry( 372 struct configuration_entry *config_entry, const char *mp_name) 373{ 374 cache_entry *result; 375 376 TRACE_IN(configuration_entry_find_mp_cache_entry); 377 result = bsearch(mp_name, config_entry->mp_cache_entries, 378 config_entry->mp_cache_entries_size, 379 sizeof(cache_entry), configuration_entry_cache_mp_cmp); 380 381 if (result == NULL) { 382 TRACE_OUT(configuration_entry_find_mp_cache_entry); 383 return (NULL); 384 } else { 385 TRACE_OUT(configuration_entry_find_mp_cache_entry); 386 return (*result); 387 } 388} 389 390/* 391 * Searches for all multipart entries with names starting with mp_name. 392 * Needed for cache flushing. 393 */ 394int 395configuration_entry_find_mp_cache_entries( 396 struct configuration_entry *config_entry, const char *mp_name, 397 cache_entry **start, cache_entry **finish) 398{ 399 cache_entry *result; 400 401 TRACE_IN(configuration_entry_find_mp_cache_entries); 402 result = bsearch(mp_name, config_entry->mp_cache_entries, 403 config_entry->mp_cache_entries_size, 404 sizeof(cache_entry), configuration_entry_cache_mp_part_cmp); 405 406 if (result == NULL) { 407 TRACE_OUT(configuration_entry_find_mp_cache_entries); 408 return (-1); 409 } 410 411 *start = result; 412 *finish = result + 1; 413 414 while (*start != config_entry->mp_cache_entries) { 415 if (configuration_entry_cache_mp_part_cmp(mp_name, *start - 1) == 0) 416 *start = *start - 1; 417 else 418 break; 419 } 420 421 while (*finish != config_entry->mp_cache_entries + 422 config_entry->mp_cache_entries_size) { 423 424 if (configuration_entry_cache_mp_part_cmp( 425 mp_name, *finish) == 0) 426 *finish = *finish + 1; 427 else 428 break; 429 } 430 431 TRACE_OUT(configuration_entry_find_mp_cache_entries); 432 return (0); 433} 434 435/* 436 * Configuration entry uses rwlock to handle access to its fields. 437 */ 438void 439configuration_lock_rdlock(struct configuration *config) 440{ 441 TRACE_IN(configuration_lock_rdlock); 442 pthread_rwlock_rdlock(&config->rwlock); 443 TRACE_OUT(configuration_lock_rdlock); 444} 445 446void 447configuration_lock_wrlock(struct configuration *config) 448{ 449 TRACE_IN(configuration_lock_wrlock); 450 pthread_rwlock_wrlock(&config->rwlock); 451 TRACE_OUT(configuration_lock_wrlock); 452} 453 454void 455configuration_unlock(struct configuration *config) 456{ 457 TRACE_IN(configuration_unlock); 458 pthread_rwlock_unlock(&config->rwlock); 459 TRACE_OUT(configuration_unlock); 460} 461 462/* 463 * Configuration entry uses 3 mutexes to handle cache operations. They are 464 * acquired by configuration_lock_entry and configuration_unlock_entry 465 * functions. 466 */ 467void 468configuration_lock_entry(struct configuration_entry *entry, 469 enum config_entry_lock_type lock_type) 470{ 471 TRACE_IN(configuration_lock_entry); 472 assert(entry != NULL); 473 474 switch (lock_type) { 475 case CELT_POSITIVE: 476 pthread_mutex_lock(&entry->positive_cache_lock); 477 break; 478 case CELT_NEGATIVE: 479 pthread_mutex_lock(&entry->negative_cache_lock); 480 break; 481 case CELT_MULTIPART: 482 pthread_mutex_lock(&entry->mp_cache_lock); 483 break; 484 default: 485 /* should be unreachable */ 486 break; 487 } 488 TRACE_OUT(configuration_lock_entry); 489} 490 491void 492configuration_unlock_entry(struct configuration_entry *entry, 493 enum config_entry_lock_type lock_type) 494{ 495 TRACE_IN(configuration_unlock_entry); 496 assert(entry != NULL); 497 498 switch (lock_type) { 499 case CELT_POSITIVE: 500 pthread_mutex_unlock(&entry->positive_cache_lock); 501 break; 502 case CELT_NEGATIVE: 503 pthread_mutex_unlock(&entry->negative_cache_lock); 504 break; 505 case CELT_MULTIPART: 506 pthread_mutex_unlock(&entry->mp_cache_lock); 507 break; 508 default: 509 /* should be unreachable */ 510 break; 511 } 512 TRACE_OUT(configuration_unlock_entry); 513} 514 515struct configuration * 516init_configuration(void) 517{ 518 struct configuration *retval; 519 520 TRACE_IN(init_configuration); 521 retval = calloc(1, sizeof(*retval)); 522 assert(retval != NULL); 523 524 retval->entries_capacity = INITIAL_ENTRIES_CAPACITY; 525 retval->entries = calloc(1, 526 sizeof(*retval->entries) * 527 retval->entries_capacity); 528 assert(retval->entries != NULL); 529 530 pthread_rwlock_init(&retval->rwlock, NULL); 531 532 TRACE_OUT(init_configuration); 533 return (retval); 534} 535 536void 537fill_configuration_defaults(struct configuration *config) 538{ 539 size_t len, i; 540 541 TRACE_IN(fill_configuration_defaults); 542 assert(config != NULL); 543 544 if (config->socket_path != NULL) 545 free(config->socket_path); 546 547 len = strlen(DEFAULT_SOCKET_PATH); 548 config->socket_path = calloc(1, len + 1); 549 assert(config->socket_path != NULL); 550 memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len); 551 552 len = strlen(DEFAULT_PIDFILE_PATH); 553 config->pidfile_path = calloc(1, len + 1); 554 assert(config->pidfile_path != NULL); 555 memcpy(config->pidfile_path, DEFAULT_PIDFILE_PATH, len); 556 557 config->socket_mode = S_IFSOCK | S_IRUSR | S_IWUSR | 558 S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 559 config->force_unlink = 1; 560 561 config->query_timeout = DEFAULT_QUERY_TIMEOUT; 562 config->threads_num = DEFAULT_THREADS_NUM; 563 564 for (i = 0; i < config->entries_size; ++i) 565 destroy_configuration_entry(config->entries[i]); 566 config->entries_size = 0; 567 568 TRACE_OUT(fill_configuration_defaults); 569} 570 571void 572destroy_configuration(struct configuration *config) 573{ 574 unsigned int i; 575 576 TRACE_IN(destroy_configuration); 577 assert(config != NULL); 578 free(config->pidfile_path); 579 free(config->socket_path); 580 581 for (i = 0; i < config->entries_size; ++i) 582 destroy_configuration_entry(config->entries[i]); 583 free(config->entries); 584 585 pthread_rwlock_destroy(&config->rwlock); 586 free(config); 587 TRACE_OUT(destroy_configuration); 588} 589