1 /*- 2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/usr.sbin/nscd/config.c,v 1.3 2008/10/12 00:44:27 delphij Exp $ 27 */ 28 29 #include <assert.h> 30 #include <math.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include "config.h" 35 #include "debug.h" 36 #include "log.h" 37 38 /* 39 * Default entries, which always exist in the configuration 40 */ 41 const char *c_default_entries[6] = { 42 NSDB_PASSWD, 43 NSDB_GROUP, 44 NSDB_HOSTS, 45 NSDB_SERVICES, 46 NSDB_PROTOCOLS, 47 NSDB_RPC 48 }; 49 50 static int configuration_entry_cmp(const void *, const void *); 51 static int configuration_entry_sort_cmp(const void *, const void *); 52 static int configuration_entry_cache_mp_sort_cmp(const void *, const void *); 53 static int configuration_entry_cache_mp_cmp(const void *, const void *); 54 static int configuration_entry_cache_mp_part_cmp(const void *, const void *); 55 static struct configuration_entry *create_configuration_entry(const char *, 56 struct timeval const *, struct timeval const *, 57 struct common_cache_entry_params const *, 58 struct common_cache_entry_params const *, 59 struct mp_cache_entry_params const *); 60 61 static int 62 configuration_entry_sort_cmp(const void *e1, const void *e2) 63 { 64 return (strcmp((*((struct configuration_entry **)e1))->name, 65 (*((struct configuration_entry **)e2))->name 66 )); 67 } 68 69 static int 70 configuration_entry_cmp(const void *e1, const void *e2) 71 { 72 return (strcmp((const char *)e1, 73 (*((struct configuration_entry **)e2))->name 74 )); 75 } 76 77 static int 78 configuration_entry_cache_mp_sort_cmp(const void *e1, const void *e2) 79 { 80 return (strcmp((*((cache_entry *)e1))->params->entry_name, 81 (*((cache_entry *)e2))->params->entry_name 82 )); 83 } 84 85 static int 86 configuration_entry_cache_mp_cmp(const void *e1, const void *e2) 87 { 88 return (strcmp((const char *)e1, 89 (*((cache_entry *)e2))->params->entry_name 90 )); 91 } 92 93 static int 94 configuration_entry_cache_mp_part_cmp(const void *e1, const void *e2) 95 { 96 return (strncmp((const char *)e1, 97 (*((cache_entry *)e2))->params->entry_name, 98 strlen((const char *)e1) 99 )); 100 } 101 102 static struct configuration_entry * 103 create_configuration_entry(const char *name, 104 struct timeval const *common_timeout, 105 struct timeval const *mp_timeout, 106 struct common_cache_entry_params const *positive_params, 107 struct common_cache_entry_params const *negative_params, 108 struct mp_cache_entry_params const *mp_params) 109 { 110 struct configuration_entry *retval; 111 size_t size; 112 int res; 113 114 TRACE_IN(create_configuration_entry); 115 assert(name != NULL); 116 assert(positive_params != NULL); 117 assert(negative_params != NULL); 118 assert(mp_params != NULL); 119 120 retval = (struct configuration_entry *)calloc(1, 121 sizeof(struct configuration_entry)); 122 assert(retval != NULL); 123 124 res = pthread_mutex_init(&retval->positive_cache_lock, NULL); 125 if (res != 0) { 126 free(retval); 127 LOG_ERR_2("create_configuration_entry", 128 "can't create positive cache lock"); 129 TRACE_OUT(create_configuration_entry); 130 return (NULL); 131 } 132 133 res = pthread_mutex_init(&retval->negative_cache_lock, NULL); 134 if (res != 0) { 135 pthread_mutex_destroy(&retval->positive_cache_lock); 136 free(retval); 137 LOG_ERR_2("create_configuration_entry", 138 "can't create negative cache lock"); 139 TRACE_OUT(create_configuration_entry); 140 return (NULL); 141 } 142 143 res = pthread_mutex_init(&retval->mp_cache_lock, NULL); 144 if (res != 0) { 145 pthread_mutex_destroy(&retval->positive_cache_lock); 146 pthread_mutex_destroy(&retval->negative_cache_lock); 147 free(retval); 148 LOG_ERR_2("create_configuration_entry", 149 "can't create negative cache lock"); 150 TRACE_OUT(create_configuration_entry); 151 return (NULL); 152 } 153 154 memcpy(&retval->positive_cache_params, positive_params, 155 sizeof(struct common_cache_entry_params)); 156 memcpy(&retval->negative_cache_params, negative_params, 157 sizeof(struct common_cache_entry_params)); 158 memcpy(&retval->mp_cache_params, mp_params, 159 sizeof(struct mp_cache_entry_params)); 160 161 size = strlen(name); 162 retval->name = (char *)calloc(1, size + 1); 163 assert(retval->name != NULL); 164 memcpy(retval->name, name, size); 165 166 memcpy(&retval->common_query_timeout, common_timeout, 167 sizeof(struct timeval)); 168 memcpy(&retval->mp_query_timeout, mp_timeout, 169 sizeof(struct timeval)); 170 171 asprintf(&retval->positive_cache_params.entry_name, "%s+", name); 172 assert(retval->positive_cache_params.entry_name != NULL); 173 174 asprintf(&retval->negative_cache_params.entry_name, "%s-", name); 175 assert(retval->negative_cache_params.entry_name != NULL); 176 177 asprintf(&retval->mp_cache_params.entry_name, "%s*", name); 178 assert(retval->mp_cache_params.entry_name != NULL); 179 180 TRACE_OUT(create_configuration_entry); 181 return (retval); 182 } 183 184 /* 185 * Creates configuration entry and fills it with default values 186 */ 187 struct configuration_entry * 188 create_def_configuration_entry(const char *name) 189 { 190 struct common_cache_entry_params positive_params, negative_params; 191 struct mp_cache_entry_params mp_params; 192 struct timeval default_common_timeout, default_mp_timeout; 193 194 struct configuration_entry *res = NULL; 195 196 TRACE_IN(create_def_configuration_entry); 197 memset(&positive_params, 0, 198 sizeof(struct common_cache_entry_params)); 199 positive_params.entry_type = CET_COMMON; 200 positive_params.cache_entries_size = DEFAULT_CACHE_HT_SIZE; 201 positive_params.max_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE; 202 positive_params.satisf_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE / 2; 203 positive_params.max_lifetime.tv_sec = DEFAULT_POSITIVE_LIFETIME; 204 positive_params.policy = CPT_LRU; 205 206 memcpy(&negative_params, &positive_params, 207 sizeof(struct common_cache_entry_params)); 208 negative_params.max_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE; 209 negative_params.satisf_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE / 2; 210 negative_params.max_lifetime.tv_sec = DEFAULT_NEGATIVE_LIFETIME; 211 negative_params.policy = CPT_FIFO; 212 213 memset(&default_common_timeout, 0, sizeof(struct timeval)); 214 default_common_timeout.tv_sec = DEFAULT_COMMON_ENTRY_TIMEOUT; 215 216 memset(&default_mp_timeout, 0, sizeof(struct timeval)); 217 default_mp_timeout.tv_sec = DEFAULT_MP_ENTRY_TIMEOUT; 218 219 memset(&mp_params, 0, 220 sizeof(struct mp_cache_entry_params)); 221 mp_params.entry_type = CET_MULTIPART; 222 mp_params.max_elemsize = DEFAULT_MULTIPART_ELEMENTS_SIZE; 223 mp_params.max_sessions = DEFAULT_MULITPART_SESSIONS_SIZE; 224 mp_params.max_lifetime.tv_sec = DEFAULT_MULITPART_LIFETIME; 225 226 res = create_configuration_entry(name, &default_common_timeout, 227 &default_mp_timeout, &positive_params, &negative_params, 228 &mp_params); 229 230 TRACE_OUT(create_def_configuration_entry); 231 return (res); 232 } 233 234 void 235 destroy_configuration_entry(struct configuration_entry *entry) 236 { 237 TRACE_IN(destroy_configuration_entry); 238 assert(entry != NULL); 239 pthread_mutex_destroy(&entry->positive_cache_lock); 240 pthread_mutex_destroy(&entry->negative_cache_lock); 241 pthread_mutex_destroy(&entry->mp_cache_lock); 242 free(entry->name); 243 free(entry->positive_cache_params.entry_name); 244 free(entry->negative_cache_params.entry_name); 245 free(entry->mp_cache_params.entry_name); 246 free(entry->mp_cache_entries); 247 free(entry); 248 TRACE_OUT(destroy_configuration_entry); 249 } 250 251 int 252 add_configuration_entry(struct configuration *config, 253 struct configuration_entry *entry) 254 { 255 TRACE_IN(add_configuration_entry); 256 assert(entry != NULL); 257 assert(entry->name != NULL); 258 if (configuration_find_entry(config, entry->name) != NULL) { 259 TRACE_OUT(add_configuration_entry); 260 return (-1); 261 } 262 263 if (config->entries_size == config->entries_capacity) { 264 struct configuration_entry **new_entries; 265 266 config->entries_capacity *= 2; 267 new_entries = (struct configuration_entry **)calloc(1, 268 sizeof(struct configuration_entry *) * 269 config->entries_capacity); 270 assert(new_entries != NULL); 271 memcpy(new_entries, config->entries, 272 sizeof(struct configuration_entry *) * 273 config->entries_size); 274 275 free(config->entries); 276 config->entries = new_entries; 277 } 278 279 config->entries[config->entries_size++] = entry; 280 qsort(config->entries, config->entries_size, 281 sizeof(struct configuration_entry *), 282 configuration_entry_sort_cmp); 283 284 TRACE_OUT(add_configuration_entry); 285 return (0); 286 } 287 288 size_t 289 configuration_get_entries_size(struct configuration *config) 290 { 291 TRACE_IN(configuration_get_entries_size); 292 assert(config != NULL); 293 TRACE_OUT(configuration_get_entries_size); 294 return (config->entries_size); 295 } 296 297 struct configuration_entry * 298 configuration_get_entry(struct configuration *config, size_t index) 299 { 300 TRACE_IN(configuration_get_entry); 301 assert(config != NULL); 302 assert(index < config->entries_size); 303 TRACE_OUT(configuration_get_entry); 304 return (config->entries[index]); 305 } 306 307 struct configuration_entry * 308 configuration_find_entry(struct configuration *config, 309 const char *name) 310 { 311 struct configuration_entry **retval; 312 313 TRACE_IN(configuration_find_entry); 314 315 retval = bsearch(name, config->entries, config->entries_size, 316 sizeof(struct configuration_entry *), configuration_entry_cmp); 317 TRACE_OUT(configuration_find_entry); 318 319 return ((retval != NULL) ? *retval : NULL); 320 } 321 322 /* 323 * All multipart cache entries are stored in the configuration_entry in the 324 * sorted array (sorted by names). The 3 functions below manage this array. 325 */ 326 327 int 328 configuration_entry_add_mp_cache_entry(struct configuration_entry *config_entry, 329 cache_entry c_entry) 330 { 331 cache_entry *new_mp_entries, *old_mp_entries; 332 333 TRACE_IN(configuration_entry_add_mp_cache_entry); 334 ++config_entry->mp_cache_entries_size; 335 new_mp_entries = (cache_entry *)malloc(sizeof(cache_entry) * 336 config_entry->mp_cache_entries_size); 337 assert(new_mp_entries != NULL); 338 new_mp_entries[0] = c_entry; 339 340 if (config_entry->mp_cache_entries_size - 1 > 0) { 341 memcpy(new_mp_entries + 1, 342 config_entry->mp_cache_entries, 343 (config_entry->mp_cache_entries_size - 1) * 344 sizeof(cache_entry)); 345 } 346 347 old_mp_entries = config_entry->mp_cache_entries; 348 config_entry->mp_cache_entries = new_mp_entries; 349 free(old_mp_entries); 350 351 qsort(config_entry->mp_cache_entries, 352 config_entry->mp_cache_entries_size, 353 sizeof(cache_entry), 354 configuration_entry_cache_mp_sort_cmp); 355 356 TRACE_OUT(configuration_entry_add_mp_cache_entry); 357 return (0); 358 } 359 360 cache_entry 361 configuration_entry_find_mp_cache_entry( 362 struct configuration_entry *config_entry, const char *mp_name) 363 { 364 cache_entry *result; 365 366 TRACE_IN(configuration_entry_find_mp_cache_entry); 367 result = bsearch(mp_name, config_entry->mp_cache_entries, 368 config_entry->mp_cache_entries_size, 369 sizeof(cache_entry), configuration_entry_cache_mp_cmp); 370 371 if (result == NULL) { 372 TRACE_OUT(configuration_entry_find_mp_cache_entry); 373 return (NULL); 374 } else { 375 TRACE_OUT(configuration_entry_find_mp_cache_entry); 376 return (*result); 377 } 378 } 379 380 /* 381 * Searches for all multipart entries with names starting with mp_name. 382 * Needed for cache flushing. 383 */ 384 int 385 configuration_entry_find_mp_cache_entries( 386 struct configuration_entry *config_entry, const char *mp_name, 387 cache_entry **start, cache_entry **finish) 388 { 389 cache_entry *result; 390 391 TRACE_IN(configuration_entry_find_mp_cache_entries); 392 result = bsearch(mp_name, config_entry->mp_cache_entries, 393 config_entry->mp_cache_entries_size, 394 sizeof(cache_entry), configuration_entry_cache_mp_part_cmp); 395 396 if (result == NULL) { 397 TRACE_OUT(configuration_entry_find_mp_cache_entries); 398 return (-1); 399 } 400 401 *start = result; 402 *finish = result + 1; 403 404 while (*start != config_entry->mp_cache_entries) { 405 if (configuration_entry_cache_mp_part_cmp(mp_name, *start - 1) == 0) 406 *start = *start - 1; 407 else 408 break; 409 } 410 411 while (*finish != config_entry->mp_cache_entries + 412 config_entry->mp_cache_entries_size) { 413 414 if (configuration_entry_cache_mp_part_cmp( 415 mp_name, *finish) == 0) 416 *finish = *finish + 1; 417 else 418 break; 419 } 420 421 TRACE_OUT(configuration_entry_find_mp_cache_entries); 422 return (0); 423 } 424 425 /* 426 * Configuration entry uses rwlock to handle access to its fields. 427 */ 428 void 429 configuration_lock_rdlock(struct configuration *config) 430 { 431 TRACE_IN(configuration_lock_rdlock); 432 pthread_rwlock_rdlock(&config->rwlock); 433 TRACE_OUT(configuration_lock_rdlock); 434 } 435 436 void 437 configuration_lock_wrlock(struct configuration *config) 438 { 439 TRACE_IN(configuration_lock_wrlock); 440 pthread_rwlock_wrlock(&config->rwlock); 441 TRACE_OUT(configuration_lock_wrlock); 442 } 443 444 void 445 configuration_unlock(struct configuration *config) 446 { 447 TRACE_IN(configuration_unlock); 448 pthread_rwlock_unlock(&config->rwlock); 449 TRACE_OUT(configuration_unlock); 450 } 451 452 /* 453 * Configuration entry uses 3 mutexes to handle cache operations. They are 454 * acquired by configuration_lock_entry and configuration_unlock_entry 455 * functions. 456 */ 457 void 458 configuration_lock_entry(struct configuration_entry *entry, 459 enum config_entry_lock_type lock_type) 460 { 461 TRACE_IN(configuration_lock_entry); 462 assert(entry != NULL); 463 464 switch (lock_type) { 465 case CELT_POSITIVE: 466 pthread_mutex_lock(&entry->positive_cache_lock); 467 break; 468 case CELT_NEGATIVE: 469 pthread_mutex_lock(&entry->negative_cache_lock); 470 break; 471 case CELT_MULTIPART: 472 pthread_mutex_lock(&entry->mp_cache_lock); 473 break; 474 default: 475 /* should be unreachable */ 476 break; 477 } 478 TRACE_OUT(configuration_lock_entry); 479 } 480 481 void 482 configuration_unlock_entry(struct configuration_entry *entry, 483 enum config_entry_lock_type lock_type) 484 { 485 TRACE_IN(configuration_unlock_entry); 486 assert(entry != NULL); 487 488 switch (lock_type) { 489 case CELT_POSITIVE: 490 pthread_mutex_unlock(&entry->positive_cache_lock); 491 break; 492 case CELT_NEGATIVE: 493 pthread_mutex_unlock(&entry->negative_cache_lock); 494 break; 495 case CELT_MULTIPART: 496 pthread_mutex_unlock(&entry->mp_cache_lock); 497 break; 498 default: 499 /* should be unreachable */ 500 break; 501 } 502 TRACE_OUT(configuration_unlock_entry); 503 } 504 505 struct configuration * 506 init_configuration(void) 507 { 508 struct configuration *retval; 509 510 TRACE_IN(init_configuration); 511 retval = (struct configuration *)calloc(1, sizeof(struct configuration)); 512 assert(retval != NULL); 513 514 retval->entries_capacity = INITIAL_ENTRIES_CAPACITY; 515 retval->entries = (struct configuration_entry **)calloc(1, 516 sizeof(struct configuration_entry *) * 517 retval->entries_capacity); 518 assert(retval->entries != NULL); 519 520 pthread_rwlock_init(&retval->rwlock, NULL); 521 522 TRACE_OUT(init_configuration); 523 return (retval); 524 } 525 526 void 527 fill_configuration_defaults(struct configuration *config) 528 { 529 size_t len, i; 530 531 TRACE_IN(fill_configuration_defaults); 532 assert(config != NULL); 533 534 if (config->socket_path != NULL) 535 free(config->socket_path); 536 537 len = strlen(DEFAULT_SOCKET_PATH); 538 config->socket_path = (char *)calloc(1, len + 1); 539 assert(config->socket_path != NULL); 540 memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len); 541 542 len = strlen(DEFAULT_PIDFILE_PATH); 543 config->pidfile_path = (char *)calloc(1, len + 1); 544 assert(config->pidfile_path != NULL); 545 memcpy(config->pidfile_path, DEFAULT_PIDFILE_PATH, len); 546 547 config->socket_mode = S_IFSOCK | S_IRUSR | S_IWUSR | 548 S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 549 config->force_unlink = 1; 550 551 config->query_timeout = DEFAULT_QUERY_TIMEOUT; 552 config->threads_num = DEFAULT_THREADS_NUM; 553 554 for (i = 0; i < config->entries_size; ++i) 555 destroy_configuration_entry(config->entries[i]); 556 config->entries_size = 0; 557 558 TRACE_OUT(fill_configuration_defaults); 559 } 560 561 void 562 destroy_configuration(struct configuration *config) 563 { 564 int i; 565 TRACE_IN(destroy_configuration); 566 assert(config != NULL); 567 free(config->pidfile_path); 568 free(config->socket_path); 569 570 for (i = 0; i < config->entries_size; ++i) 571 destroy_configuration_entry(config->entries[i]); 572 free(config->entries); 573 574 pthread_rwlock_destroy(&config->rwlock); 575 free(config); 576 TRACE_OUT(destroy_configuration); 577 } 578