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 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/stat.h> 32 #include <sys/time.h> 33 34 #include <assert.h> 35 #include <math.h> 36 #include <nsswitch.h> 37 #include <pthread.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 42 #include "config.h" 43 #include "debug.h" 44 #include "log.h" 45 46 /* 47 * Default entries, which always exist in the configuration 48 */ 49 const char *c_default_entries[6] = { 50 NSDB_PASSWD, 51 NSDB_GROUP, 52 NSDB_HOSTS, 53 NSDB_SERVICES, 54 NSDB_PROTOCOLS, 55 NSDB_RPC 56 }; 57 58 static int configuration_entry_cmp(const void *, const void *); 59 static int configuration_entry_sort_cmp(const void *, const void *); 60 static int configuration_entry_cache_mp_sort_cmp(const void *, const void *); 61 static int configuration_entry_cache_mp_cmp(const void *, const void *); 62 static int configuration_entry_cache_mp_part_cmp(const void *, const void *); 63 static struct configuration_entry *create_configuration_entry(const char *, 64 struct timeval const *, struct timeval const *, 65 struct common_cache_entry_params const *, 66 struct common_cache_entry_params const *, 67 struct mp_cache_entry_params const *); 68 69 static int 70 configuration_entry_sort_cmp(const void *e1, const void *e2) 71 { 72 return (strcmp((*((struct configuration_entry **)e1))->name, 73 (*((struct configuration_entry **)e2))->name 74 )); 75 } 76 77 static int 78 configuration_entry_cmp(const void *e1, const void *e2) 79 { 80 return (strcmp((const char *)e1, 81 (*((struct configuration_entry **)e2))->name 82 )); 83 } 84 85 static int 86 configuration_entry_cache_mp_sort_cmp(const void *e1, const void *e2) 87 { 88 return (strcmp((*((cache_entry *)e1))->params->entry_name, 89 (*((cache_entry *)e2))->params->entry_name 90 )); 91 } 92 93 static int 94 configuration_entry_cache_mp_cmp(const void *e1, const void *e2) 95 { 96 return (strcmp((const char *)e1, 97 (*((cache_entry *)e2))->params->entry_name 98 )); 99 } 100 101 static int 102 configuration_entry_cache_mp_part_cmp(const void *e1, const void *e2) 103 { 104 return (strncmp((const char *)e1, 105 (*((cache_entry *)e2))->params->entry_name, 106 strlen((const char *)e1) 107 )); 108 } 109 110 static struct configuration_entry * 111 create_configuration_entry(const char *name, 112 struct timeval const *common_timeout, 113 struct timeval const *mp_timeout, 114 struct common_cache_entry_params const *positive_params, 115 struct common_cache_entry_params const *negative_params, 116 struct mp_cache_entry_params const *mp_params) 117 { 118 struct configuration_entry *retval; 119 size_t size; 120 int res; 121 122 TRACE_IN(create_configuration_entry); 123 assert(name != NULL); 124 assert(positive_params != NULL); 125 assert(negative_params != NULL); 126 assert(mp_params != NULL); 127 128 retval = calloc(1, 129 sizeof(*retval)); 130 assert(retval != NULL); 131 132 res = pthread_mutex_init(&retval->positive_cache_lock, NULL); 133 if (res != 0) { 134 free(retval); 135 LOG_ERR_2("create_configuration_entry", 136 "can't create positive cache lock"); 137 TRACE_OUT(create_configuration_entry); 138 return (NULL); 139 } 140 141 res = pthread_mutex_init(&retval->negative_cache_lock, NULL); 142 if (res != 0) { 143 pthread_mutex_destroy(&retval->positive_cache_lock); 144 free(retval); 145 LOG_ERR_2("create_configuration_entry", 146 "can't create negative cache lock"); 147 TRACE_OUT(create_configuration_entry); 148 return (NULL); 149 } 150 151 res = pthread_mutex_init(&retval->mp_cache_lock, NULL); 152 if (res != 0) { 153 pthread_mutex_destroy(&retval->positive_cache_lock); 154 pthread_mutex_destroy(&retval->negative_cache_lock); 155 free(retval); 156 LOG_ERR_2("create_configuration_entry", 157 "can't create negative cache lock"); 158 TRACE_OUT(create_configuration_entry); 159 return (NULL); 160 } 161 162 memcpy(&retval->positive_cache_params, positive_params, 163 sizeof(struct common_cache_entry_params)); 164 memcpy(&retval->negative_cache_params, negative_params, 165 sizeof(struct common_cache_entry_params)); 166 memcpy(&retval->mp_cache_params, mp_params, 167 sizeof(struct mp_cache_entry_params)); 168 169 size = strlen(name); 170 retval->name = calloc(1, size + 1); 171 assert(retval->name != NULL); 172 memcpy(retval->name, name, size); 173 174 memcpy(&retval->common_query_timeout, common_timeout, 175 sizeof(struct timeval)); 176 memcpy(&retval->mp_query_timeout, mp_timeout, 177 sizeof(struct timeval)); 178 179 asprintf(&retval->positive_cache_params.cep.entry_name, "%s+", name); 180 assert(retval->positive_cache_params.cep.entry_name != NULL); 181 182 asprintf(&retval->negative_cache_params.cep.entry_name, "%s-", name); 183 assert(retval->negative_cache_params.cep.entry_name != NULL); 184 185 asprintf(&retval->mp_cache_params.cep.entry_name, "%s*", name); 186 assert(retval->mp_cache_params.cep.entry_name != NULL); 187 188 TRACE_OUT(create_configuration_entry); 189 return (retval); 190 } 191 192 /* 193 * Creates configuration entry and fills it with default values 194 */ 195 struct configuration_entry * 196 create_def_configuration_entry(const char *name) 197 { 198 struct common_cache_entry_params positive_params, negative_params; 199 struct mp_cache_entry_params mp_params; 200 struct timeval default_common_timeout, default_mp_timeout; 201 202 struct configuration_entry *res = NULL; 203 204 TRACE_IN(create_def_configuration_entry); 205 memset(&positive_params, 0, 206 sizeof(struct common_cache_entry_params)); 207 positive_params.cep.entry_type = CET_COMMON; 208 positive_params.cache_entries_size = DEFAULT_CACHE_HT_SIZE; 209 positive_params.max_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE; 210 positive_params.satisf_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE / 2; 211 positive_params.max_lifetime.tv_sec = DEFAULT_POSITIVE_LIFETIME; 212 positive_params.confidence_threshold = DEFAULT_POSITIVE_CONF_THRESH; 213 positive_params.policy = CPT_LRU; 214 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 244 void 245 destroy_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 261 int 262 add_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(config->entries_capacity, 278 sizeof(*new_entries)); 279 assert(new_entries != NULL); 280 memcpy(new_entries, config->entries, 281 sizeof(struct configuration_entry *) * 282 config->entries_size); 283 284 free(config->entries); 285 config->entries = new_entries; 286 } 287 288 config->entries[config->entries_size++] = entry; 289 qsort(config->entries, config->entries_size, 290 sizeof(struct configuration_entry *), 291 configuration_entry_sort_cmp); 292 293 TRACE_OUT(add_configuration_entry); 294 return (0); 295 } 296 297 size_t 298 configuration_get_entries_size(struct configuration *config) 299 { 300 TRACE_IN(configuration_get_entries_size); 301 assert(config != NULL); 302 TRACE_OUT(configuration_get_entries_size); 303 return (config->entries_size); 304 } 305 306 struct configuration_entry * 307 configuration_get_entry(struct configuration *config, size_t index) 308 { 309 TRACE_IN(configuration_get_entry); 310 assert(config != NULL); 311 assert(index < config->entries_size); 312 TRACE_OUT(configuration_get_entry); 313 return (config->entries[index]); 314 } 315 316 struct configuration_entry * 317 configuration_find_entry(struct configuration *config, 318 const char *name) 319 { 320 struct configuration_entry **retval; 321 322 TRACE_IN(configuration_find_entry); 323 324 retval = bsearch(name, config->entries, config->entries_size, 325 sizeof(struct configuration_entry *), configuration_entry_cmp); 326 TRACE_OUT(configuration_find_entry); 327 328 return ((retval != NULL) ? *retval : NULL); 329 } 330 331 /* 332 * All multipart cache entries are stored in the configuration_entry in the 333 * sorted array (sorted by names). The 3 functions below manage this array. 334 */ 335 336 int 337 configuration_entry_add_mp_cache_entry(struct configuration_entry *config_entry, 338 cache_entry c_entry) 339 { 340 cache_entry *new_mp_entries, *old_mp_entries; 341 342 TRACE_IN(configuration_entry_add_mp_cache_entry); 343 ++config_entry->mp_cache_entries_size; 344 new_mp_entries = malloc(sizeof(*new_mp_entries) * 345 config_entry->mp_cache_entries_size); 346 assert(new_mp_entries != NULL); 347 new_mp_entries[0] = c_entry; 348 349 if (config_entry->mp_cache_entries_size - 1 > 0) { 350 memcpy(new_mp_entries + 1, 351 config_entry->mp_cache_entries, 352 (config_entry->mp_cache_entries_size - 1) * 353 sizeof(cache_entry)); 354 } 355 356 old_mp_entries = config_entry->mp_cache_entries; 357 config_entry->mp_cache_entries = new_mp_entries; 358 free(old_mp_entries); 359 360 qsort(config_entry->mp_cache_entries, 361 config_entry->mp_cache_entries_size, 362 sizeof(cache_entry), 363 configuration_entry_cache_mp_sort_cmp); 364 365 TRACE_OUT(configuration_entry_add_mp_cache_entry); 366 return (0); 367 } 368 369 cache_entry 370 configuration_entry_find_mp_cache_entry( 371 struct configuration_entry *config_entry, const char *mp_name) 372 { 373 cache_entry *result; 374 375 TRACE_IN(configuration_entry_find_mp_cache_entry); 376 result = bsearch(mp_name, config_entry->mp_cache_entries, 377 config_entry->mp_cache_entries_size, 378 sizeof(cache_entry), configuration_entry_cache_mp_cmp); 379 380 if (result == NULL) { 381 TRACE_OUT(configuration_entry_find_mp_cache_entry); 382 return (NULL); 383 } else { 384 TRACE_OUT(configuration_entry_find_mp_cache_entry); 385 return (*result); 386 } 387 } 388 389 /* 390 * Searches for all multipart entries with names starting with mp_name. 391 * Needed for cache flushing. 392 */ 393 int 394 configuration_entry_find_mp_cache_entries( 395 struct configuration_entry *config_entry, const char *mp_name, 396 cache_entry **start, cache_entry **finish) 397 { 398 cache_entry *result; 399 400 TRACE_IN(configuration_entry_find_mp_cache_entries); 401 result = bsearch(mp_name, config_entry->mp_cache_entries, 402 config_entry->mp_cache_entries_size, 403 sizeof(cache_entry), configuration_entry_cache_mp_part_cmp); 404 405 if (result == NULL) { 406 TRACE_OUT(configuration_entry_find_mp_cache_entries); 407 return (-1); 408 } 409 410 *start = result; 411 *finish = result + 1; 412 413 while (*start != config_entry->mp_cache_entries) { 414 if (configuration_entry_cache_mp_part_cmp(mp_name, *start - 1) == 0) 415 *start = *start - 1; 416 else 417 break; 418 } 419 420 while (*finish != config_entry->mp_cache_entries + 421 config_entry->mp_cache_entries_size) { 422 423 if (configuration_entry_cache_mp_part_cmp( 424 mp_name, *finish) == 0) 425 *finish = *finish + 1; 426 else 427 break; 428 } 429 430 TRACE_OUT(configuration_entry_find_mp_cache_entries); 431 return (0); 432 } 433 434 /* 435 * Configuration entry uses rwlock to handle access to its fields. 436 */ 437 void 438 configuration_lock_rdlock(struct configuration *config) 439 { 440 TRACE_IN(configuration_lock_rdlock); 441 pthread_rwlock_rdlock(&config->rwlock); 442 TRACE_OUT(configuration_lock_rdlock); 443 } 444 445 void 446 configuration_lock_wrlock(struct configuration *config) 447 { 448 TRACE_IN(configuration_lock_wrlock); 449 pthread_rwlock_wrlock(&config->rwlock); 450 TRACE_OUT(configuration_lock_wrlock); 451 } 452 453 void 454 configuration_unlock(struct configuration *config) 455 { 456 TRACE_IN(configuration_unlock); 457 pthread_rwlock_unlock(&config->rwlock); 458 TRACE_OUT(configuration_unlock); 459 } 460 461 /* 462 * Configuration entry uses 3 mutexes to handle cache operations. They are 463 * acquired by configuration_lock_entry and configuration_unlock_entry 464 * functions. 465 */ 466 void 467 configuration_lock_entry(struct configuration_entry *entry, 468 enum config_entry_lock_type lock_type) 469 { 470 TRACE_IN(configuration_lock_entry); 471 assert(entry != NULL); 472 473 switch (lock_type) { 474 case CELT_POSITIVE: 475 pthread_mutex_lock(&entry->positive_cache_lock); 476 break; 477 case CELT_NEGATIVE: 478 pthread_mutex_lock(&entry->negative_cache_lock); 479 break; 480 case CELT_MULTIPART: 481 pthread_mutex_lock(&entry->mp_cache_lock); 482 break; 483 default: 484 /* should be unreachable */ 485 break; 486 } 487 TRACE_OUT(configuration_lock_entry); 488 } 489 490 void 491 configuration_unlock_entry(struct configuration_entry *entry, 492 enum config_entry_lock_type lock_type) 493 { 494 TRACE_IN(configuration_unlock_entry); 495 assert(entry != NULL); 496 497 switch (lock_type) { 498 case CELT_POSITIVE: 499 pthread_mutex_unlock(&entry->positive_cache_lock); 500 break; 501 case CELT_NEGATIVE: 502 pthread_mutex_unlock(&entry->negative_cache_lock); 503 break; 504 case CELT_MULTIPART: 505 pthread_mutex_unlock(&entry->mp_cache_lock); 506 break; 507 default: 508 /* should be unreachable */ 509 break; 510 } 511 TRACE_OUT(configuration_unlock_entry); 512 } 513 514 struct configuration * 515 init_configuration(void) 516 { 517 struct configuration *retval; 518 519 TRACE_IN(init_configuration); 520 retval = calloc(1, sizeof(*retval)); 521 assert(retval != NULL); 522 523 retval->entries_capacity = INITIAL_ENTRIES_CAPACITY; 524 retval->entries = calloc(retval->entries_capacity, 525 sizeof(*retval->entries)); 526 assert(retval->entries != NULL); 527 528 pthread_rwlock_init(&retval->rwlock, NULL); 529 530 TRACE_OUT(init_configuration); 531 return (retval); 532 } 533 534 void 535 fill_configuration_defaults(struct configuration *config) 536 { 537 size_t len, i; 538 539 TRACE_IN(fill_configuration_defaults); 540 assert(config != NULL); 541 542 if (config->socket_path != NULL) 543 free(config->socket_path); 544 545 len = strlen(DEFAULT_SOCKET_PATH); 546 config->socket_path = calloc(1, len + 1); 547 assert(config->socket_path != NULL); 548 memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len); 549 550 len = strlen(DEFAULT_PIDFILE_PATH); 551 config->pidfile_path = calloc(1, len + 1); 552 assert(config->pidfile_path != NULL); 553 memcpy(config->pidfile_path, DEFAULT_PIDFILE_PATH, len); 554 555 config->socket_mode = S_IFSOCK | S_IRUSR | S_IWUSR | 556 S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 557 config->force_unlink = 1; 558 559 config->query_timeout = DEFAULT_QUERY_TIMEOUT; 560 config->threads_num = DEFAULT_THREADS_NUM; 561 562 for (i = 0; i < config->entries_size; ++i) 563 destroy_configuration_entry(config->entries[i]); 564 config->entries_size = 0; 565 566 TRACE_OUT(fill_configuration_defaults); 567 } 568 569 void 570 destroy_configuration(struct configuration *config) 571 { 572 unsigned int i; 573 574 TRACE_IN(destroy_configuration); 575 assert(config != NULL); 576 free(config->pidfile_path); 577 free(config->socket_path); 578 579 for (i = 0; i < config->entries_size; ++i) 580 destroy_configuration_entry(config->entries[i]); 581 free(config->entries); 582 583 pthread_rwlock_destroy(&config->rwlock); 584 free(config); 585 TRACE_OUT(destroy_configuration); 586 } 587