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