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: 61704 $")
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 time(&ast_lastreloadtime);
00219
00220 if (!name || !strcasecmp(name, "extconfig")) {
00221 read_config_maps();
00222 reloaded = 2;
00223 }
00224 if (!name || !strcasecmp(name, "manager")) {
00225 reload_manager();
00226 reloaded = 2;
00227 }
00228 if (!name || !strcasecmp(name, "cdr")) {
00229 ast_cdr_engine_reload();
00230 reloaded = 2;
00231 }
00232 if (!name || !strcasecmp(name, "enum")) {
00233 ast_enum_reload();
00234 reloaded = 2;
00235 }
00236 if (!name || !strcasecmp(name, "rtp")) {
00237 ast_rtp_reload();
00238 reloaded = 2;
00239 }
00240 if (!name || !strcasecmp(name, "dnsmgr")) {
00241 dnsmgr_reload();
00242 reloaded = 2;
00243 }
00244
00245 ast_mutex_lock(&modlock);
00246 oldversion = modlistver;
00247 m = module_list;
00248 while(m) {
00249 if (!name || !strcasecmp(name, m->resource)) {
00250 if (reloaded < 1)
00251 reloaded = 1;
00252 reload = m->reload;
00253 ast_mutex_unlock(&modlock);
00254 if (reload) {
00255 reloaded = 2;
00256 if (option_verbose > 2)
00257 ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", m->resource, m->description());
00258 reload();
00259 }
00260 ast_mutex_lock(&modlock);
00261 if (oldversion != modlistver)
00262 break;
00263 }
00264 m = m->next;
00265 }
00266 ast_mutex_unlock(&modlock);
00267 ast_mutex_unlock(&reloadlock);
00268 return reloaded;
00269 }
00270
00271 static int __load_resource(const char *resource_name, const struct ast_config *cfg)
00272 {
00273 static char fn[256];
00274 int errors=0;
00275 int res;
00276 struct module *m;
00277 int flags=RTLD_NOW;
00278 #ifdef RTLD_GLOBAL
00279 char *val;
00280 #endif
00281 unsigned char *key;
00282 char tmp[80];
00283
00284 if (strncasecmp(resource_name, "res_", 4)) {
00285 #ifdef RTLD_GLOBAL
00286 if (cfg) {
00287 if ((val = ast_variable_retrieve(cfg, "global", resource_name))
00288 && ast_true(val))
00289 flags |= RTLD_GLOBAL;
00290 }
00291 #endif
00292 } else {
00293
00294 #ifdef RTLD_GLOBAL
00295 flags = (RTLD_GLOBAL | RTLD_LAZY);
00296 #else
00297 flags = RTLD_LAZY;
00298 #endif
00299 }
00300
00301 if (ast_mutex_lock(&modlock))
00302 ast_log(LOG_WARNING, "Failed to lock\n");
00303 m = module_list;
00304 while(m) {
00305 if (!strcasecmp(m->resource, resource_name)) {
00306 ast_log(LOG_WARNING, "Module '%s' already exists\n", resource_name);
00307 ast_mutex_unlock(&modlock);
00308 return -1;
00309 }
00310 m = m->next;
00311 }
00312 m = malloc(sizeof(struct module));
00313 if (!m) {
00314 ast_log(LOG_WARNING, "Out of memory\n");
00315 ast_mutex_unlock(&modlock);
00316 return -1;
00317 }
00318 strncpy(m->resource, resource_name, sizeof(m->resource)-1);
00319 if (resource_name[0] == '/') {
00320 strncpy(fn, resource_name, sizeof(fn)-1);
00321 } else {
00322 snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_MODULE_DIR, resource_name);
00323 }
00324 m->lib = dlopen(fn, flags);
00325 if (!m->lib) {
00326 ast_log(LOG_WARNING, "%s\n", dlerror());
00327 free(m);
00328 ast_mutex_unlock(&modlock);
00329 return -1;
00330 }
00331 m->load_module = dlsym(m->lib, "load_module");
00332 if (m->load_module == NULL)
00333 m->load_module = dlsym(m->lib, "_load_module");
00334 if (!m->load_module) {
00335 ast_log(LOG_WARNING, "No load_module in module %s\n", fn);
00336 errors++;
00337 }
00338 m->unload_module = dlsym(m->lib, "unload_module");
00339 if (m->unload_module == NULL)
00340 m->unload_module = dlsym(m->lib, "_unload_module");
00341 if (!m->unload_module) {
00342 ast_log(LOG_WARNING, "No unload_module in module %s\n", fn);
00343 errors++;
00344 }
00345 m->usecount = dlsym(m->lib, "usecount");
00346 if (m->usecount == NULL)
00347 m->usecount = dlsym(m->lib, "_usecount");
00348 if (!m->usecount) {
00349 ast_log(LOG_WARNING, "No usecount in module %s\n", fn);
00350 errors++;
00351 }
00352 m->description = dlsym(m->lib, "description");
00353 if (m->description == NULL)
00354 m->description = dlsym(m->lib, "_description");
00355 if (!m->description) {
00356 ast_log(LOG_WARNING, "No description in module %s\n", fn);
00357 errors++;
00358 }
00359 m->key = dlsym(m->lib, "key");
00360 if (m->key == NULL)
00361 m->key = dlsym(m->lib, "_key");
00362 if (!m->key) {
00363 ast_log(LOG_WARNING, "No key routine in module %s\n", fn);
00364 errors++;
00365 }
00366
00367 m->reload = dlsym(m->lib, "reload");
00368 if (m->reload == NULL)
00369 m->reload = dlsym(m->lib, "_reload");
00370
00371 if (!m->key || !(key = (unsigned char *) m->key())) {
00372 ast_log(LOG_WARNING, "Key routine returned NULL in module %s\n", fn);
00373 key = NULL;
00374 errors++;
00375 }
00376 if (key && verify_key(key)) {
00377 ast_log(LOG_WARNING, "Unexpected key returned by module %s\n", fn);
00378 errors++;
00379 }
00380 if (errors) {
00381 ast_log(LOG_WARNING, "%d error%s loading module %s, aborted\n", errors, (errors != 1) ? "s" : "", fn);
00382 dlclose(m->lib);
00383 free(m);
00384 ast_mutex_unlock(&modlock);
00385 return -1;
00386 }
00387 if (!fully_booted) {
00388 if (option_verbose)
00389 ast_verbose( " => (%s)\n", term_color(tmp, m->description(), COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
00390 if (option_console && !option_verbose)
00391 ast_verbose( ".");
00392 } else {
00393 if (option_verbose)
00394 ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", fn, m->description());
00395 }
00396
00397
00398
00399 m->next = NULL;
00400 if (module_list == NULL) {
00401
00402 module_list = m;
00403 }
00404 else {
00405 struct module *i;
00406
00407 for (i = module_list; i->next; i = i->next)
00408 ;
00409 i->next = m;
00410 }
00411
00412 modlistver = rand();
00413 ast_mutex_unlock(&modlock);
00414 if ((res = m->load_module())) {
00415 ast_log(LOG_WARNING, "%s: load_module failed, returning %d\n", m->resource, res);
00416 ast_unload_resource(resource_name, 0);
00417 return -1;
00418 }
00419 ast_update_use_count();
00420 return 0;
00421 }
00422
00423 int ast_load_resource(const char *resource_name)
00424 {
00425 int o;
00426 struct ast_config *cfg = NULL;
00427 int res;
00428
00429
00430 o = option_verbose;
00431 option_verbose = 0;
00432 cfg = ast_config_load(AST_MODULE_CONFIG);
00433 option_verbose = o;
00434 res = __load_resource(resource_name, cfg);
00435 if (cfg)
00436 ast_config_destroy(cfg);
00437 return res;
00438 }
00439
00440 static int ast_resource_exists(char *resource)
00441 {
00442 struct module *m;
00443 if (ast_mutex_lock(&modlock))
00444 ast_log(LOG_WARNING, "Failed to lock\n");
00445 m = module_list;
00446 while(m) {
00447 if (!strcasecmp(resource, m->resource))
00448 break;
00449 m = m->next;
00450 }
00451 ast_mutex_unlock(&modlock);
00452 if (m)
00453 return -1;
00454 else
00455 return 0;
00456 }
00457
00458 static const char *loadorder[] =
00459 {
00460 "res_",
00461 "pbx_",
00462 "chan_",
00463 NULL,
00464 };
00465
00466 int load_modules(const int preload_only)
00467 {
00468 struct ast_config *cfg;
00469 struct ast_variable *v;
00470 char tmp[80];
00471
00472 if (option_verbose) {
00473 if (preload_only)
00474 ast_verbose("Asterisk Dynamic Loader loading preload modules:\n");
00475 else
00476 ast_verbose("Asterisk Dynamic Loader Starting:\n");
00477 }
00478
00479 cfg = ast_config_load(AST_MODULE_CONFIG);
00480 if (cfg) {
00481 int doload;
00482
00483
00484 for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
00485 doload = 0;
00486
00487 if (preload_only)
00488 doload = !strcasecmp(v->name, "preload");
00489 else
00490 doload = !strcasecmp(v->name, "load");
00491
00492 if (doload) {
00493 if (option_debug && !option_verbose)
00494 ast_log(LOG_DEBUG, "Loading module %s\n", v->value);
00495 if (option_verbose) {
00496 ast_verbose(VERBOSE_PREFIX_1 "[%s]", term_color(tmp, v->value, COLOR_BRWHITE, 0, sizeof(tmp)));
00497 fflush(stdout);
00498 }
00499 if (__load_resource(v->value, cfg)) {
00500 ast_log(LOG_WARNING, "Loading module %s failed!\n", v->value);
00501 ast_config_destroy(cfg);
00502 return -1;
00503 }
00504 }
00505 }
00506 }
00507
00508 if (preload_only) {
00509 ast_config_destroy(cfg);
00510 return 0;
00511 }
00512
00513 if (!cfg || ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
00514
00515 DIR *mods;
00516 struct dirent *d;
00517 int x;
00518
00519
00520 for (x=0; x<sizeof(loadorder) / sizeof(loadorder[0]); x++) {
00521 mods = opendir((char *)ast_config_AST_MODULE_DIR);
00522 if (mods) {
00523 while((d = readdir(mods))) {
00524
00525 if ((strlen(d->d_name) > 3) &&
00526 (!loadorder[x] || !strncasecmp(d->d_name, loadorder[x], strlen(loadorder[x]))) &&
00527 !strcasecmp(d->d_name + strlen(d->d_name) - 3, ".so") &&
00528 !ast_resource_exists(d->d_name)) {
00529
00530
00531 if (cfg) {
00532 v = ast_variable_browse(cfg, "modules");
00533 while(v) {
00534 if (!strcasecmp(v->name, "noload") &&
00535 !strcasecmp(v->value, d->d_name))
00536 break;
00537 v = v->next;
00538 }
00539 if (v) {
00540 if (option_verbose) {
00541 ast_verbose( VERBOSE_PREFIX_1 "[skipping %s]\n", d->d_name);
00542 fflush(stdout);
00543 }
00544 continue;
00545 }
00546
00547 }
00548 if (option_debug && !option_verbose)
00549 ast_log(LOG_DEBUG, "Loading module %s\n", d->d_name);
00550 if (option_verbose) {
00551 ast_verbose( VERBOSE_PREFIX_1 "[%s]", term_color(tmp, d->d_name, COLOR_BRWHITE, 0, sizeof(tmp)));
00552 fflush(stdout);
00553 }
00554 if (__load_resource(d->d_name, cfg)) {
00555 ast_log(LOG_WARNING, "Loading module %s failed!\n", d->d_name);
00556 if (cfg)
00557 ast_config_destroy(cfg);
00558 return -1;
00559 }
00560 }
00561 }
00562 closedir(mods);
00563 } else {
00564 if (!option_quiet)
00565 ast_log(LOG_WARNING, "Unable to open modules directory %s.\n", (char *)ast_config_AST_MODULE_DIR);
00566 }
00567 }
00568 }
00569 ast_config_destroy(cfg);
00570 return 0;
00571 }
00572
00573 void ast_update_use_count(void)
00574 {
00575
00576
00577 struct loadupdate *m;
00578 if (ast_mutex_lock(&modlock))
00579 ast_log(LOG_WARNING, "Failed to lock\n");
00580 m = updaters;
00581 while(m) {
00582 m->updater();
00583 m = m->next;
00584 }
00585 ast_mutex_unlock(&modlock);
00586
00587 }
00588
00589 int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
00590 const char *like)
00591 {
00592 struct module *m;
00593 int unlock = -1;
00594 int total_mod_loaded = 0;
00595
00596 if (ast_mutex_trylock(&modlock))
00597 unlock = 0;
00598 m = module_list;
00599 while (m) {
00600 total_mod_loaded += modentry(m->resource, m->description(), m->usecount(), like);
00601 m = m->next;
00602 }
00603 if (unlock)
00604 ast_mutex_unlock(&modlock);
00605
00606 return total_mod_loaded;
00607 }
00608
00609 int ast_loader_register(int (*v)(void))
00610 {
00611 struct loadupdate *tmp;
00612
00613 if ((tmp = malloc(sizeof (struct loadupdate)))) {
00614 tmp->updater = v;
00615 if (ast_mutex_lock(&modlock))
00616 ast_log(LOG_WARNING, "Failed to lock\n");
00617 tmp->next = updaters;
00618 updaters = tmp;
00619 ast_mutex_unlock(&modlock);
00620 return 0;
00621 }
00622 return -1;
00623 }
00624
00625 int ast_loader_unregister(int (*v)(void))
00626 {
00627 int res = -1;
00628 struct loadupdate *tmp, *tmpl=NULL;
00629 if (ast_mutex_lock(&modlock))
00630 ast_log(LOG_WARNING, "Failed to lock\n");
00631 tmp = updaters;
00632 while(tmp) {
00633 if (tmp->updater == v) {
00634 if (tmpl)
00635 tmpl->next = tmp->next;
00636 else
00637 updaters = tmp->next;
00638 break;
00639 }
00640 tmpl = tmp;
00641 tmp = tmp->next;
00642 }
00643 if (tmp)
00644 res = 0;
00645 ast_mutex_unlock(&modlock);
00646 return res;
00647 }