00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdio.h>
00026 #include <dirent.h>
00027 #include <unistd.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030
00031 #include "asterisk.h"
00032
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 8162 $")
00034
00035 #include "asterisk/module.h"
00036 #include "asterisk/options.h"
00037 #include "asterisk/config.h"
00038 #include "asterisk/logger.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/term.h"
00041 #include "asterisk/manager.h"
00042 #include "asterisk/cdr.h"
00043 #include "asterisk/enum.h"
00044 #include "asterisk/rtp.h"
00045 #include "asterisk/lock.h"
00046 #ifdef DLFCNCOMPAT
00047 #include "asterisk/dlfcn-compat.h"
00048 #else
00049 #include <dlfcn.h>
00050 #endif
00051 #include "asterisk/md5.h"
00052
00053 #ifndef RTLD_NOW
00054 #define RTLD_NOW 0
00055 #endif
00056
00057 AST_MUTEX_DEFINE_STATIC(modlock);
00058 AST_MUTEX_DEFINE_STATIC(reloadlock);
00059
00060 static struct module *module_list=NULL;
00061 static int modlistver = 0;
00062
00063 static unsigned char expected_key[] =
00064 { 0x8e, 0x93, 0x22, 0x83, 0xf5, 0xc3, 0xc0, 0x75,
00065 0xff, 0x8b, 0xa9, 0xbe, 0x7c, 0x43, 0x74, 0x63 };
00066
00067 struct module {
00068 int (*load_module)(void);
00069 int (*unload_module)(void);
00070 int (*usecount)(void);
00071 char *(*description)(void);
00072 char *(*key)(void);
00073 int (*reload)(void);
00074 void *lib;
00075 char resource[256];
00076 struct module *next;
00077 };
00078
00079 static struct loadupdate {
00080 int (*updater)(void);
00081 struct loadupdate *next;
00082 } *updaters = NULL;
00083
00084 static int printdigest(unsigned char *d)
00085 {
00086 int x;
00087 char buf[256];
00088 char buf2[16];
00089 snprintf(buf, sizeof(buf), "Unexpected signature:");
00090 for (x=0; x<16; x++) {
00091 snprintf(buf2, sizeof(buf2), " %02x", *(d++));
00092 strcat(buf, buf2);
00093 }
00094 strcat(buf, "\n");
00095 ast_log(LOG_DEBUG, "%s", buf);
00096 return 0;
00097 }
00098
00099 static int key_matches(unsigned char *key1, unsigned char *key2)
00100 {
00101 int match = 1;
00102 int x;
00103 for (x=0; x<16; x++) {
00104 match &= (key1[x] == key2[x]);
00105 }
00106 return match;
00107 }
00108
00109 static int verify_key(unsigned char *key)
00110 {
00111 struct MD5Context c;
00112 unsigned char digest[16];
00113 MD5Init(&c);
00114 MD5Update(&c, key, strlen((char *)key));
00115 MD5Final(digest, &c);
00116 if (key_matches(expected_key, digest))
00117 return 0;
00118 printdigest(digest);
00119 return -1;
00120 }
00121
00122 int ast_unload_resource(const char *resource_name, int force)
00123 {
00124 struct module *m, *ml = NULL;
00125 int res = -1;
00126 if (ast_mutex_lock(&modlock))
00127 ast_log(LOG_WARNING, "Failed to lock\n");
00128 m = module_list;
00129 while(m) {
00130 if (!strcasecmp(m->resource, resource_name)) {
00131 if ((res = m->usecount()) > 0) {
00132 if (force)
00133 ast_log(LOG_WARNING, "Warning: Forcing removal of module %s with use count %d\n", resource_name, res);
00134 else {
00135 ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name, res);
00136 ast_mutex_unlock(&modlock);
00137 return -1;
00138 }
00139 }
00140 res = m->unload_module();
00141 if (res) {
00142 ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
00143 if (force <= AST_FORCE_FIRM) {
00144 ast_mutex_unlock(&modlock);
00145 return -1;
00146 } else
00147 ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
00148 }
00149 if (ml)
00150 ml->next = m->next;
00151 else
00152 module_list = m->next;
00153 dlclose(m->lib);
00154 free(m);
00155 break;
00156 }
00157 ml = m;
00158 m = m->next;
00159 }
00160 modlistver = rand();
00161 ast_mutex_unlock(&modlock);
00162 ast_update_use_count();
00163 return res;
00164 }
00165
00166 char *ast_module_helper(char *line, char *word, int pos, int state, int rpos, int needsreload)
00167 {
00168 struct module *m;
00169 int which=0;
00170 char *ret;
00171
00172 if (pos != rpos)
00173 return NULL;
00174 ast_mutex_lock(&modlock);
00175 m = module_list;
00176 while(m) {
00177 if (!strncasecmp(word, m->resource, strlen(word)) && (m->reload || !needsreload)) {
00178 if (++which > state)
00179 break;
00180 }
00181 m = m->next;
00182 }
00183 if (m) {
00184 ret = strdup(m->resource);
00185 } else {
00186 ret = NULL;
00187 if (!strncasecmp(word, "extconfig", strlen(word))) {
00188 if (++which > state)
00189 ret = strdup("extconfig");
00190 } else if (!strncasecmp(word, "manager", strlen(word))) {
00191 if (++which > state)
00192 ret = strdup("manager");
00193 } else if (!strncasecmp(word, "enum", strlen(word))) {
00194 if (++which > state)
00195 ret = strdup("enum");
00196 } else if (!strncasecmp(word, "rtp", strlen(word))) {
00197 if (++which > state)
00198 ret = strdup("rtp");
00199 }
00200
00201 }
00202 ast_mutex_unlock(&modlock);
00203 return ret;
00204 }
00205
00206 int ast_module_reload(const char *name)
00207 {
00208 struct module *m;
00209 int reloaded = 0;
00210 int oldversion;
00211 int (*reload)(void);
00212
00213
00214 if (ast_mutex_trylock(&reloadlock)) {
00215 ast_verbose("The previous reload command didn't finish yet\n");
00216 return -1;
00217 }
00218 if (!name || !strcasecmp(name, "extconfig")) {
00219 read_config_maps();
00220 reloaded = 2;
00221 }
00222 if (!name || !strcasecmp(name, "manager")) {
00223 reload_manager();
00224 reloaded = 2;
00225 }
00226 if (!name || !strcasecmp(name, "cdr")) {
00227 ast_cdr_engine_reload();
00228 reloaded = 2;
00229 }
00230 if (!name || !strcasecmp(name, "enum")) {
00231 ast_enum_reload();
00232 reloaded = 2;
00233 }
00234 if (!name || !strcasecmp(name, "rtp")) {
00235 ast_rtp_reload();
00236 reloaded = 2;
00237 }
00238 if (!name || !strcasecmp(name, "dnsmgr")) {
00239 dnsmgr_reload();
00240 reloaded = 2;
00241 }
00242 time(&ast_lastreloadtime);
00243
00244 ast_mutex_lock(&modlock);
00245 oldversion = modlistver;
00246 m = module_list;
00247 while(m) {
00248 if (!name || !strcasecmp(name, m->resource)) {
00249 if (reloaded < 1)
00250 reloaded = 1;
00251 reload = m->reload;
00252 ast_mutex_unlock(&modlock);
00253 if (reload) {
00254 reloaded = 2;
00255 if (option_verbose > 2)
00256 ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", m->resource, m->description());
00257 reload();
00258 }
00259 ast_mutex_lock(&modlock);
00260 if (oldversion != modlistver)
00261 break;
00262 }
00263 m = m->next;
00264 }
00265 ast_mutex_unlock(&modlock);
00266 ast_mutex_unlock(&reloadlock);
00267 return reloaded;
00268 }
00269
00270 static int __load_resource(const char *resource_name, const struct ast_config *cfg)
00271 {
00272 static char fn[256];
00273 int errors=0;
00274 int res;
00275 struct module *m;
00276 int flags=RTLD_NOW;
00277 #ifdef RTLD_GLOBAL
00278 char *val;
00279 #endif
00280 unsigned char *key;
00281 char tmp[80];
00282
00283 if (strncasecmp(resource_name, "res_", 4)) {
00284 #ifdef RTLD_GLOBAL
00285 if (cfg) {
00286 if ((val = ast_variable_retrieve(cfg, "global", resource_name))
00287 && ast_true(val))
00288 flags |= RTLD_GLOBAL;
00289 }
00290 #endif
00291 } else {
00292
00293 #ifdef RTLD_GLOBAL
00294 flags = (RTLD_GLOBAL | RTLD_LAZY);
00295 #else
00296 flags = RTLD_LAZY;
00297 #endif
00298 }
00299
00300 if (ast_mutex_lock(&modlock))
00301 ast_log(LOG_WARNING, "Failed to lock\n");
00302 m = module_list;
00303 while(m) {
00304 if (!strcasecmp(m->resource, resource_name)) {
00305 ast_log(LOG_WARNING, "Module '%s' already exists\n", resource_name);
00306 ast_mutex_unlock(&modlock);
00307 return -1;
00308 }
00309 m = m->next;
00310 }
00311 m = malloc(sizeof(struct module));
00312 if (!m) {
00313 ast_log(LOG_WARNING, "Out of memory\n");
00314 ast_mutex_unlock(&modlock);
00315 return -1;
00316 }
00317 strncpy(m->resource, resource_name, sizeof(m->resource)-1);
00318 if (resource_name[0] == '/') {
00319 strncpy(fn, resource_name, sizeof(fn)-1);
00320 } else {
00321 snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_MODULE_DIR, resource_name);
00322 }
00323 m->lib = dlopen(fn, flags);
00324 if (!m->lib) {
00325 ast_log(LOG_WARNING, "%s\n", dlerror());
00326 free(m);
00327 ast_mutex_unlock(&modlock);
00328 return -1;
00329 }
00330 m->load_module = dlsym(m->lib, "load_module");
00331 if (m->load_module == NULL)
00332 m->load_module = dlsym(m->lib, "_load_module");
00333 if (!m->load_module) {
00334 ast_log(LOG_WARNING, "No load_module in module %s\n", fn);
00335 errors++;
00336 }
00337 m->unload_module = dlsym(m->lib, "unload_module");
00338 if (m->unload_module == NULL)
00339 m->unload_module = dlsym(m->lib, "_unload_module");
00340 if (!m->unload_module) {
00341 ast_log(LOG_WARNING, "No unload_module in module %s\n", fn);
00342 errors++;
00343 }
00344 m->usecount = dlsym(m->lib, "usecount");
00345 if (m->usecount == NULL)
00346 m->usecount = dlsym(m->lib, "_usecount");
00347 if (!m->usecount) {
00348 ast_log(LOG_WARNING, "No usecount in module %s\n", fn);
00349 errors++;
00350 }
00351 m->description = dlsym(m->lib, "description");
00352 if (m->description == NULL)
00353 m->description = dlsym(m->lib, "_description");
00354 if (!m->description) {
00355 ast_log(LOG_WARNING, "No description in module %s\n", fn);
00356 errors++;
00357 }
00358 m->key = dlsym(m->lib, "key");
00359 if (m->key == NULL)
00360 m->key = dlsym(m->lib, "_key");
00361 if (!m->key) {
00362 ast_log(LOG_WARNING, "No key routine in module %s\n", fn);
00363 errors++;
00364 }
00365
00366 m->reload = dlsym(m->lib, "reload");
00367 if (m->reload == NULL)
00368 m->reload = dlsym(m->lib, "_reload");
00369
00370 if (!m->key || !(key = (unsigned char *) m->key())) {
00371 ast_log(LOG_WARNING, "Key routine returned NULL in module %s\n", fn);
00372 key = NULL;
00373 errors++;
00374 }
00375 if (key && verify_key(key)) {
00376 ast_log(LOG_WARNING, "Unexpected key returned by module %s\n", fn);
00377 errors++;
00378 }
00379 if (errors) {
00380 ast_log(LOG_WARNING, "%d error%s loading module %s, aborted\n", errors, (errors != 1) ? "s" : "", fn);
00381 dlclose(m->lib);
00382 free(m);
00383 ast_mutex_unlock(&modlock);
00384 return -1;
00385 }
00386 if (!fully_booted) {
00387 if (option_verbose)
00388 ast_verbose( " => (%s)\n", term_color(tmp, m->description(), COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
00389 if (option_console && !option_verbose)
00390 ast_verbose( ".");
00391 } else {
00392 if (option_verbose)
00393 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", fn, m->description());
00394 }
00395
00396
00397
00398 m->next = NULL;
00399 if (module_list == NULL) {
00400
00401 module_list = m;
00402 }
00403 else {
00404 struct module *i;
00405
00406 for (i = module_list; i->next; i = i->next)
00407 ;
00408 i->next = m;
00409 }
00410
00411 modlistver = rand();
00412 ast_mutex_unlock(&modlock);
00413 if ((res = m->load_module())) {
00414 ast_log(LOG_WARNING, "%s: load_module failed, returning %d\n", m->resource, res);
00415 ast_unload_resource(resource_name, 0);
00416 return -1;
00417 }
00418 ast_update_use_count();
00419 return 0;
00420 }
00421
00422 int ast_load_resource(const char *resource_name)
00423 {
00424 int o;
00425 struct ast_config *cfg = NULL;
00426 int res;
00427
00428
00429 o = option_verbose;
00430 option_verbose = 0;
00431 cfg = ast_config_load(AST_MODULE_CONFIG);
00432 option_verbose = o;
00433 res = __load_resource(resource_name, cfg);
00434 if (cfg)
00435 ast_config_destroy(cfg);
00436 return res;
00437 }
00438
00439 static int ast_resource_exists(char *resource)
00440 {
00441 struct module *m;
00442 if (ast_mutex_lock(&modlock))
00443 ast_log(LOG_WARNING, "Failed to lock\n");
00444 m = module_list;
00445 while(m) {
00446 if (!strcasecmp(resource, m->resource))
00447 break;
00448 m = m->next;
00449 }
00450 ast_mutex_unlock(&modlock);
00451 if (m)
00452 return -1;
00453 else
00454 return 0;
00455 }
00456
00457 static const char *loadorder[] =
00458 {
00459 "res_",
00460 "pbx_",
00461 "chan_",
00462 NULL,
00463 };
00464
00465 int load_modules(const int preload_only)
00466 {
00467 struct ast_config *cfg;
00468 struct ast_variable *v;
00469 char tmp[80];
00470
00471 if (option_verbose) {
00472 if (preload_only)
00473 ast_verbose("Asterisk Dynamic Loader loading preload modules:\n");
00474 else
00475 ast_verbose("Asterisk Dynamic Loader Starting:\n");
00476 }
00477
00478 cfg = ast_config_load(AST_MODULE_CONFIG);
00479 if (cfg) {
00480 int doload;
00481
00482
00483 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
00484 doload = 0;
00485
00486 if (preload_only)
00487 doload = !strcasecmp(v->name, "preload");
00488 else
00489 doload = !strcasecmp(v->name, "load");
00490
00491 if (doload) {
00492 if (option_debug && !option_verbose)
00493 ast_log(LOG_DEBUG, "Loading module %s\n", v->value);
00494 if (option_verbose) {
00495 ast_verbose(VERBOSE_PREFIX_1 "[%s]", term_color(tmp, v->value, COLOR_BRWHITE, 0, sizeof(tmp)));
00496 fflush(stdout);
00497 }
00498 if (__load_resource(v->value, cfg)) {
00499 ast_log(LOG_WARNING, "Loading module %s failed!\n", v->value);
00500 ast_config_destroy(cfg);
00501 return -1;
00502 }
00503 }
00504 }
00505 }
00506
00507 if (preload_only) {
00508 ast_config_destroy(cfg);
00509 return 0;
00510 }
00511
00512 if (!cfg || ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
00513
00514 DIR *mods;
00515 struct dirent *d;
00516 int x;
00517
00518
00519 for (x=0; x<sizeof(loadorder) / sizeof(loadorder[0]); x++) {
00520 mods = opendir((char *)ast_config_AST_MODULE_DIR);
00521 if (mods) {
00522 while((d = readdir(mods))) {
00523
00524 if ((strlen(d->d_name) > 3) &&
00525 (!loadorder[x] || !strncasecmp(d->d_name, loadorder[x], strlen(loadorder[x]))) &&
00526 !strcasecmp(d->d_name + strlen(d->d_name) - 3, ".so") &&
00527 !ast_resource_exists(d->d_name)) {
00528
00529
00530 if (cfg) {
00531 v = ast_variable_browse(cfg, "modules");
00532 while(v) {
00533 if (!strcasecmp(v->name, "noload") &&
00534 !strcasecmp(v->value, d->d_name))
00535 break;
00536 v = v->next;
00537 }
00538 if (v) {
00539 if (option_verbose) {
00540 ast_verbose( VERBOSE_PREFIX_1 "[skipping %s]\n", d->d_name);
00541 fflush(stdout);
00542 }
00543 continue;
00544 }
00545
00546 }
00547 if (option_debug && !option_verbose)
00548 ast_log(LOG_DEBUG, "Loading module %s\n", d->d_name);
00549 if (option_verbose) {
00550 ast_verbose( VERBOSE_PREFIX_1 "[%s]", term_color(tmp, d->d_name, COLOR_BRWHITE, 0, sizeof(tmp)));
00551 fflush(stdout);
00552 }
00553 if (__load_resource(d->d_name, cfg)) {
00554 ast_log(LOG_WARNING, "Loading module %s failed!\n", d->d_name);
00555 if (cfg)
00556 ast_config_destroy(cfg);
00557 return -1;
00558 }
00559 }
00560 }
00561 closedir(mods);
00562 } else {
00563 if (!option_quiet)
00564 ast_log(LOG_WARNING, "Unable to open modules directory %s.\n", (char *)ast_config_AST_MODULE_DIR);
00565 }
00566 }
00567 }
00568 ast_config_destroy(cfg);
00569 return 0;
00570 }
00571
00572 void ast_update_use_count(void)
00573 {
00574
00575
00576 struct loadupdate *m;
00577 if (ast_mutex_lock(&modlock))
00578 ast_log(LOG_WARNING, "Failed to lock\n");
00579 m = updaters;
00580 while(m) {
00581 m->updater();
00582 m = m->next;
00583 }
00584 ast_mutex_unlock(&modlock);
00585
00586 }
00587
00588 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
00589 const char *like)
00590 {
00591 struct module *m;
00592 int unlock = -1;
00593 int total_mod_loaded = 0;
00594
00595 if (ast_mutex_trylock(&modlock))
00596 unlock = 0;
00597 m = module_list;
00598 while (m) {
00599 total_mod_loaded += modentry(m->resource, m->description(), m->usecount(), like);
00600 m = m->next;
00601 }
00602 if (unlock)
00603 ast_mutex_unlock(&modlock);
00604
00605 return total_mod_loaded;
00606 }
00607
00608 int ast_loader_register(int (*v)(void))
00609 {
00610 struct loadupdate *tmp;
00611
00612 if ((tmp = malloc(sizeof (struct loadupdate)))) {
00613 tmp->updater = v;
00614 if (ast_mutex_lock(&modlock))
00615 ast_log(LOG_WARNING, "Failed to lock\n");
00616 tmp->next = updaters;
00617 updaters = tmp;
00618 ast_mutex_unlock(&modlock);
00619 return 0;
00620 }
00621 return -1;
00622 }
00623
00624 int ast_loader_unregister(int (*v)(void))
00625 {
00626 int res = -1;
00627 struct loadupdate *tmp, *tmpl=NULL;
00628 if (ast_mutex_lock(&modlock))
00629 ast_log(LOG_WARNING, "Failed to lock\n");
00630 tmp = updaters;
00631 while(tmp) {
00632 if (tmp->updater == v) {
00633 if (tmpl)
00634 tmpl->next = tmp->next;
00635 else
00636 updaters = tmp->next;
00637 break;
00638 }
00639 tmpl = tmp;
00640 tmp = tmp->next;
00641 }
00642 if (tmp)
00643 res = 0;
00644 ast_mutex_unlock(&modlock);
00645 return res;
00646 }