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