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