~ubuntu-branches/ubuntu/maverick/asterisk/maverick-security

« back to all changes in this revision

Viewing changes to .pc/h323-workaround-openh323-segfault/main/loader.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Beattie
  • Date: 2010-03-02 10:00:03 UTC
  • Revision ID: james.westby@ubuntu.com-20100302100003-qaycyl89gy31bz03
Tags: 1:1.6.2.2-1ubuntu2
debian/{control,rules}: re-enable hardened options to gain PIE build
(Debian bug 542741, LP: #527538)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Asterisk -- An open source telephony toolkit.
 
3
 *
 
4
 * Copyright (C) 1999 - 2006, Digium, Inc.
 
5
 *
 
6
 * Mark Spencer <markster@digium.com>
 
7
 * Kevin P. Fleming <kpfleming@digium.com>
 
8
 * Luigi Rizzo <rizzo@icir.org>
 
9
 *
 
10
 * See http://www.asterisk.org for more information about
 
11
 * the Asterisk project. Please do not directly contact
 
12
 * any of the maintainers of this project for assistance;
 
13
 * the project provides a web site, mailing lists and IRC
 
14
 * channels for your use.
 
15
 *
 
16
 * This program is free software, distributed under the terms of
 
17
 * the GNU General Public License Version 2. See the LICENSE file
 
18
 * at the top of the source tree.
 
19
 */
 
20
 
 
21
/*! \file
 
22
 *
 
23
 * \brief Module Loader
 
24
 * \author Mark Spencer <markster@digium.com>
 
25
 * \author Kevin P. Fleming <kpfleming@digium.com>
 
26
 * \author Luigi Rizzo <rizzo@icir.org>
 
27
 * - See ModMngMnt
 
28
 */
 
29
 
 
30
#include "asterisk.h"
 
31
 
 
32
ASTERISK_FILE_VERSION(__FILE__, "$Revision: 213453 $")
 
33
 
 
34
#include "asterisk/_private.h"
 
35
#include "asterisk/paths.h"     /* use ast_config_AST_MODULE_DIR */
 
36
#include <dirent.h>
 
37
 
 
38
#include "asterisk/linkedlists.h"
 
39
#include "asterisk/module.h"
 
40
#include "asterisk/config.h"
 
41
#include "asterisk/channel.h"
 
42
#include "asterisk/term.h"
 
43
#include "asterisk/manager.h"
 
44
#include "asterisk/cdr.h"
 
45
#include "asterisk/enum.h"
 
46
#include "asterisk/rtp.h"
 
47
#include "asterisk/http.h"
 
48
#include "asterisk/lock.h"
 
49
#include "asterisk/features.h"
 
50
#include "asterisk/dsp.h"
 
51
#include "asterisk/udptl.h"
 
52
#include "asterisk/heap.h"
 
53
 
 
54
#include <dlfcn.h>
 
55
 
 
56
#include "asterisk/md5.h"
 
57
#include "asterisk/utils.h"
 
58
 
 
59
#ifndef RTLD_NOW
 
60
#define RTLD_NOW 0
 
61
#endif
 
62
 
 
63
#ifndef RTLD_LOCAL
 
64
#define RTLD_LOCAL 0
 
65
#endif
 
66
 
 
67
struct ast_module_user {
 
68
        struct ast_channel *chan;
 
69
        AST_LIST_ENTRY(ast_module_user) entry;
 
70
};
 
71
 
 
72
AST_LIST_HEAD(module_user_list, ast_module_user);
 
73
 
 
74
static unsigned char expected_key[] =
 
75
{ 0x87, 0x76, 0x79, 0x35, 0x23, 0xea, 0x3a, 0xd3,
 
76
  0x25, 0x2a, 0xbb, 0x35, 0x87, 0xe4, 0x22, 0x24 };
 
77
 
 
78
static char buildopt_sum[33] = AST_BUILDOPT_SUM;
 
79
 
 
80
static unsigned int embedding = 1; /* we always start out by registering embedded modules,
 
81
                                      since they are here before we dlopen() any
 
82
                                   */
 
83
 
 
84
struct ast_module {
 
85
        const struct ast_module_info *info;
 
86
        void *lib;                                      /* the shared lib, or NULL if embedded */
 
87
        int usecount;                                   /* the number of 'users' currently in this module */
 
88
        struct module_user_list users;                  /* the list of users in the module */
 
89
        struct {
 
90
                unsigned int running:1;
 
91
                unsigned int declined:1;
 
92
        } flags;
 
93
        AST_LIST_ENTRY(ast_module) entry;
 
94
        char resource[0];
 
95
};
 
96
 
 
97
static AST_LIST_HEAD_STATIC(module_list, ast_module);
 
98
 
 
99
/*
 
100
 * module_list is cleared by its constructor possibly after
 
101
 * we start accumulating embedded modules, so we need to
 
102
 * use another list (without the lock) to accumulate them.
 
103
 * Then we update the main list when embedding is done.
 
104
 */
 
105
static struct module_list embedded_module_list;
 
106
 
 
107
struct loadupdate {
 
108
        int (*updater)(void);
 
109
        AST_LIST_ENTRY(loadupdate) entry;
 
110
};
 
111
 
 
112
static AST_LIST_HEAD_STATIC(updaters, loadupdate);
 
113
 
 
114
AST_MUTEX_DEFINE_STATIC(reloadlock);
 
115
 
 
116
struct reload_queue_item {
 
117
        AST_LIST_ENTRY(reload_queue_item) entry;
 
118
        char module[0];
 
119
};
 
120
 
 
121
static int do_full_reload = 0;
 
122
 
 
123
static AST_LIST_HEAD_STATIC(reload_queue, reload_queue_item);
 
124
 
 
125
/* when dynamic modules are being loaded, ast_module_register() will
 
126
   need to know what filename the module was loaded from while it
 
127
   is being registered
 
128
*/
 
129
struct ast_module *resource_being_loaded;
 
130
 
 
131
/* XXX: should we check for duplicate resource names here? */
 
132
 
 
133
void ast_module_register(const struct ast_module_info *info)
 
134
{
 
135
        struct ast_module *mod;
 
136
 
 
137
        if (embedding) {
 
138
                if (!(mod = ast_calloc(1, sizeof(*mod) + strlen(info->name) + 1)))
 
139
                        return;
 
140
                strcpy(mod->resource, info->name);
 
141
        } else {
 
142
                mod = resource_being_loaded;
 
143
        }
 
144
 
 
145
        mod->info = info;
 
146
        AST_LIST_HEAD_INIT(&mod->users);
 
147
 
 
148
        /* during startup, before the loader has been initialized,
 
149
           there are no threads, so there is no need to take the lock
 
150
           on this list to manipulate it. it is also possible that it
 
151
           might be unsafe to use the list lock at that point... so
 
152
           let's avoid it altogether
 
153
        */
 
154
        if (embedding) {
 
155
                AST_LIST_INSERT_TAIL(&embedded_module_list, mod, entry);
 
156
        } else {
 
157
                AST_LIST_LOCK(&module_list);
 
158
                /* it is paramount that the new entry be placed at the tail of
 
159
                   the list, otherwise the code that uses dlopen() to load
 
160
                   dynamic modules won't be able to find out if the module it
 
161
                   just opened was registered or failed to load
 
162
                */
 
163
                AST_LIST_INSERT_TAIL(&module_list, mod, entry);
 
164
                AST_LIST_UNLOCK(&module_list);
 
165
        }
 
166
 
 
167
        /* give the module a copy of its own handle, for later use in registrations and the like */
 
168
        *((struct ast_module **) &(info->self)) = mod;
 
169
}
 
170
 
 
171
void ast_module_unregister(const struct ast_module_info *info)
 
172
{
 
173
        struct ast_module *mod = NULL;
 
174
 
 
175
        /* it is assumed that the users list in the module structure
 
176
           will already be empty, or we cannot have gotten to this
 
177
           point
 
178
        */
 
179
        AST_LIST_LOCK(&module_list);
 
180
        AST_LIST_TRAVERSE_SAFE_BEGIN(&module_list, mod, entry) {
 
181
                if (mod->info == info) {
 
182
                        AST_LIST_REMOVE_CURRENT(entry);
 
183
                        break;
 
184
                }
 
185
        }
 
186
        AST_LIST_TRAVERSE_SAFE_END;
 
187
        AST_LIST_UNLOCK(&module_list);
 
188
 
 
189
        if (mod) {
 
190
                AST_LIST_HEAD_DESTROY(&mod->users);
 
191
                ast_free(mod);
 
192
        }
 
193
}
 
194
 
 
195
struct ast_module_user *__ast_module_user_add(struct ast_module *mod,
 
196
                                              struct ast_channel *chan)
 
197
{
 
198
        struct ast_module_user *u = ast_calloc(1, sizeof(*u));
 
199
 
 
200
        if (!u)
 
201
                return NULL;
 
202
 
 
203
        u->chan = chan;
 
204
 
 
205
        AST_LIST_LOCK(&mod->users);
 
206
        AST_LIST_INSERT_HEAD(&mod->users, u, entry);
 
207
        AST_LIST_UNLOCK(&mod->users);
 
208
 
 
209
        ast_atomic_fetchadd_int(&mod->usecount, +1);
 
210
 
 
211
        ast_update_use_count();
 
212
 
 
213
        return u;
 
214
}
 
215
 
 
216
void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
 
217
{
 
218
        AST_LIST_LOCK(&mod->users);
 
219
        AST_LIST_REMOVE(&mod->users, u, entry);
 
220
        AST_LIST_UNLOCK(&mod->users);
 
221
        ast_atomic_fetchadd_int(&mod->usecount, -1);
 
222
        ast_free(u);
 
223
 
 
224
        ast_update_use_count();
 
225
}
 
226
 
 
227
void __ast_module_user_hangup_all(struct ast_module *mod)
 
228
{
 
229
        struct ast_module_user *u;
 
230
 
 
231
        AST_LIST_LOCK(&mod->users);
 
232
        while ((u = AST_LIST_REMOVE_HEAD(&mod->users, entry))) {
 
233
                ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
 
234
                ast_atomic_fetchadd_int(&mod->usecount, -1);
 
235
                ast_free(u);
 
236
        }
 
237
        AST_LIST_UNLOCK(&mod->users);
 
238
 
 
239
        ast_update_use_count();
 
240
}
 
241
 
 
242
/*! \note
 
243
 * In addition to modules, the reload command handles some extra keywords
 
244
 * which are listed here together with the corresponding handlers.
 
245
 * This table is also used by the command completion code.
 
246
 */
 
247
static struct reload_classes {
 
248
        const char *name;
 
249
        int (*reload_fn)(void);
 
250
} reload_classes[] = {  /* list in alpha order, longest match first for cli completion */
 
251
        { "cdr",        ast_cdr_engine_reload },
 
252
        { "dnsmgr",     dnsmgr_reload },
 
253
        { "extconfig",  read_config_maps },
 
254
        { "enum",       ast_enum_reload },
 
255
        { "manager",    reload_manager },
 
256
        { "rtp",        ast_rtp_reload },
 
257
        { "http",       ast_http_reload },
 
258
        { "logger",     logger_reload },
 
259
        { "features",   ast_features_reload },
 
260
        { "dsp",        ast_dsp_reload},
 
261
        { "udptl",      ast_udptl_reload },
 
262
        { "indications", ast_indications_reload },
 
263
        { NULL,         NULL }
 
264
};
 
265
 
 
266
static int printdigest(const unsigned char *d)
 
267
{
 
268
        int x, pos;
 
269
        char buf[256]; /* large enough so we don't have to worry */
 
270
 
 
271
        for (pos = 0, x = 0; x < 16; x++)
 
272
                pos += sprintf(buf + pos, " %02x", *d++);
 
273
 
 
274
        ast_debug(1, "Unexpected signature:%s\n", buf);
 
275
 
 
276
        return 0;
 
277
}
 
278
 
 
279
static int key_matches(const unsigned char *key1, const unsigned char *key2)
 
280
{
 
281
        int x;
 
282
 
 
283
        for (x = 0; x < 16; x++) {
 
284
                if (key1[x] != key2[x])
 
285
                        return 0;
 
286
        }
 
287
 
 
288
        return 1;
 
289
}
 
290
 
 
291
static int verify_key(const unsigned char *key)
 
292
{
 
293
        struct MD5Context c;
 
294
        unsigned char digest[16];
 
295
 
 
296
        MD5Init(&c);
 
297
        MD5Update(&c, key, strlen((char *)key));
 
298
        MD5Final(digest, &c);
 
299
 
 
300
        if (key_matches(expected_key, digest))
 
301
                return 0;
 
302
 
 
303
        printdigest(digest);
 
304
 
 
305
        return -1;
 
306
}
 
307
 
 
308
static int resource_name_match(const char *name1_in, const char *name2_in)
 
309
{
 
310
        char *name1 = (char *) name1_in;
 
311
        char *name2 = (char *) name2_in;
 
312
 
 
313
        /* trim off any .so extensions */
 
314
        if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) {
 
315
                name1 = ast_strdupa(name1);
 
316
                name1[strlen(name1) - 3] = '\0';
 
317
        }
 
318
        if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) {
 
319
                name2 = ast_strdupa(name2);
 
320
                name2[strlen(name2) - 3] = '\0';
 
321
        }
 
322
 
 
323
        return strcasecmp(name1, name2);
 
324
}
 
325
 
 
326
static struct ast_module *find_resource(const char *resource, int do_lock)
 
327
{
 
328
        struct ast_module *cur;
 
329
 
 
330
        if (do_lock)
 
331
                AST_LIST_LOCK(&module_list);
 
332
 
 
333
        AST_LIST_TRAVERSE(&module_list, cur, entry) {
 
334
                if (!resource_name_match(resource, cur->resource))
 
335
                        break;
 
336
        }
 
337
 
 
338
        if (do_lock)
 
339
                AST_LIST_UNLOCK(&module_list);
 
340
 
 
341
        return cur;
 
342
}
 
343
 
 
344
#ifdef LOADABLE_MODULES
 
345
static void unload_dynamic_module(struct ast_module *mod)
 
346
{
 
347
        void *lib = mod->lib;
 
348
 
 
349
        /* WARNING: the structure pointed to by mod is going to
 
350
           disappear when this operation succeeds, so we can't
 
351
           dereference it */
 
352
 
 
353
        if (lib)
 
354
                while (!dlclose(lib));
 
355
}
 
356
 
 
357
static struct ast_module *load_dynamic_module(const char *resource_in, unsigned int global_symbols_only)
 
358
{
 
359
        char fn[PATH_MAX] = "";
 
360
        void *lib = NULL;
 
361
        struct ast_module *mod;
 
362
        unsigned int wants_global;
 
363
        int space;      /* room needed for the descriptor */
 
364
        int missing_so = 0;
 
365
 
 
366
        space = sizeof(*resource_being_loaded) + strlen(resource_in) + 1;
 
367
        if (strcasecmp(resource_in + strlen(resource_in) - 3, ".so")) {
 
368
                missing_so = 1;
 
369
                space += 3;     /* room for the extra ".so" */
 
370
        }
 
371
 
 
372
        snprintf(fn, sizeof(fn), "%s/%s%s", ast_config_AST_MODULE_DIR, resource_in, missing_so ? ".so" : "");
 
373
 
 
374
        /* make a first load of the module in 'quiet' mode... don't try to resolve
 
375
           any symbols, and don't export any symbols. this will allow us to peek into
 
376
           the module's info block (if available) to see what flags it has set */
 
377
 
 
378
        resource_being_loaded = ast_calloc(1, space);
 
379
        if (!resource_being_loaded)
 
380
                return NULL;
 
381
        strcpy(resource_being_loaded->resource, resource_in);
 
382
        if (missing_so)
 
383
                strcat(resource_being_loaded->resource, ".so");
 
384
 
 
385
        if (!(lib = dlopen(fn, RTLD_LAZY | RTLD_LOCAL))) {
 
386
                ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
 
387
                ast_free(resource_being_loaded);
 
388
                return NULL;
 
389
        }
 
390
 
 
391
        /* the dlopen() succeeded, let's find out if the module
 
392
           registered itself */
 
393
        /* note that this will only work properly as long as
 
394
           ast_module_register() (which is called by the module's
 
395
           constructor) places the new module at the tail of the
 
396
           module_list
 
397
        */
 
398
        if (resource_being_loaded != (mod = AST_LIST_LAST(&module_list))) {
 
399
                ast_log(LOG_WARNING, "Module '%s' did not register itself during load\n", resource_in);
 
400
                /* no, it did not, so close it and return */
 
401
                while (!dlclose(lib));
 
402
                /* note that the module's destructor will call ast_module_unregister(),
 
403
                   which will free the structure we allocated in resource_being_loaded */
 
404
                return NULL;
 
405
        }
 
406
 
 
407
        wants_global = ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS);
 
408
 
 
409
        /* if we are being asked only to load modules that provide global symbols,
 
410
           and this one does not, then close it and return */
 
411
        if (global_symbols_only && !wants_global) {
 
412
                while (!dlclose(lib));
 
413
                return NULL;
 
414
        }
 
415
 
 
416
        while (!dlclose(lib));
 
417
        resource_being_loaded = NULL;
 
418
 
 
419
        /* start the load process again */
 
420
        resource_being_loaded = ast_calloc(1, space);
 
421
        if (!resource_being_loaded)
 
422
                return NULL;
 
423
        strcpy(resource_being_loaded->resource, resource_in);
 
424
        if (missing_so)
 
425
                strcat(resource_being_loaded->resource, ".so");
 
426
 
 
427
        if (!(lib = dlopen(fn, wants_global ? RTLD_LAZY | RTLD_GLOBAL : RTLD_NOW | RTLD_LOCAL))) {
 
428
                ast_log(LOG_WARNING, "Error loading module '%s': %s\n", resource_in, dlerror());
 
429
                ast_free(resource_being_loaded);
 
430
                return NULL;
 
431
        }
 
432
 
 
433
        /* since the module was successfully opened, and it registered itself
 
434
           the previous time we did that, we're going to assume it worked this
 
435
           time too :) */
 
436
 
 
437
        AST_LIST_LAST(&module_list)->lib = lib;
 
438
        resource_being_loaded = NULL;
 
439
 
 
440
        return AST_LIST_LAST(&module_list);
 
441
}
 
442
#endif
 
443
 
 
444
void ast_module_shutdown(void)
 
445
{
 
446
        struct ast_module *mod;
 
447
        AST_LIST_HEAD_NOLOCK_STATIC(local_module_list, ast_module);
 
448
 
 
449
        /* We have to call the unload() callbacks in reverse order that the modules
 
450
         * exist in the module list so it is the reverse order of how they were
 
451
         * loaded. */
 
452
 
 
453
        AST_LIST_LOCK(&module_list);
 
454
        while ((mod = AST_LIST_REMOVE_HEAD(&module_list, entry)))
 
455
                AST_LIST_INSERT_HEAD(&local_module_list, mod, entry);
 
456
        AST_LIST_UNLOCK(&module_list);
 
457
 
 
458
        while ((mod = AST_LIST_REMOVE_HEAD(&local_module_list, entry))) {
 
459
                if (mod->info->unload)
 
460
                        mod->info->unload();
 
461
                /* Since this should only be called when shutting down "gracefully",
 
462
                 * all channels should be down before we get to this point, meaning
 
463
                 * there will be no module users left. */
 
464
                AST_LIST_HEAD_DESTROY(&mod->users);
 
465
                free(mod);
 
466
        }
 
467
}
 
468
 
 
469
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode force)
 
470
{
 
471
        struct ast_module *mod;
 
472
        int res = -1;
 
473
        int error = 0;
 
474
 
 
475
        AST_LIST_LOCK(&module_list);
 
476
 
 
477
        if (!(mod = find_resource(resource_name, 0))) {
 
478
                AST_LIST_UNLOCK(&module_list);
 
479
                ast_log(LOG_WARNING, "Unload failed, '%s' could not be found\n", resource_name);
 
480
                return 0;
 
481
        }
 
482
 
 
483
        if (!(mod->flags.running || mod->flags.declined))
 
484
                error = 1;
 
485
 
 
486
        if (!error && (mod->usecount > 0)) {
 
487
                if (force)
 
488
                        ast_log(LOG_WARNING, "Warning:  Forcing removal of module '%s' with use count %d\n",
 
489
                                resource_name, mod->usecount);
 
490
                else {
 
491
                        ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name,
 
492
                                mod->usecount);
 
493
                        error = 1;
 
494
                }
 
495
        }
 
496
 
 
497
        if (!error) {
 
498
                __ast_module_user_hangup_all(mod);
 
499
                res = mod->info->unload();
 
500
 
 
501
                if (res) {
 
502
                        ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
 
503
                        if (force <= AST_FORCE_FIRM)
 
504
                                error = 1;
 
505
                        else
 
506
                                ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
 
507
                }
 
508
        }
 
509
 
 
510
        if (!error)
 
511
                mod->flags.running = mod->flags.declined = 0;
 
512
 
 
513
        AST_LIST_UNLOCK(&module_list);
 
514
 
 
515
        if (!error && !mod->lib && mod->info && mod->info->restore_globals)
 
516
                mod->info->restore_globals();
 
517
 
 
518
#ifdef LOADABLE_MODULES
 
519
        if (!error)
 
520
                unload_dynamic_module(mod);
 
521
#endif
 
522
 
 
523
        if (!error)
 
524
                ast_update_use_count();
 
525
 
 
526
        return res;
 
527
}
 
528
 
 
529
char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
 
530
{
 
531
        struct ast_module *cur;
 
532
        int i, which=0, l = strlen(word);
 
533
        char *ret = NULL;
 
534
 
 
535
        if (pos != rpos)
 
536
                return NULL;
 
537
 
 
538
        AST_LIST_LOCK(&module_list);
 
539
        AST_LIST_TRAVERSE(&module_list, cur, entry) {
 
540
                if (!strncasecmp(word, cur->resource, l) &&
 
541
                    (cur->info->reload || !needsreload) &&
 
542
                    ++which > state) {
 
543
                        ret = ast_strdup(cur->resource);
 
544
                        break;
 
545
                }
 
546
        }
 
547
        AST_LIST_UNLOCK(&module_list);
 
548
 
 
549
        if (!ret) {
 
550
                for (i=0; !ret && reload_classes[i].name; i++) {
 
551
                        if (!strncasecmp(word, reload_classes[i].name, l) && ++which > state)
 
552
                                ret = ast_strdup(reload_classes[i].name);
 
553
                }
 
554
        }
 
555
 
 
556
        return ret;
 
557
}
 
558
 
 
559
void ast_process_pending_reloads(void)
 
560
{
 
561
        struct reload_queue_item *item;
 
562
 
 
563
        if (!ast_fully_booted) {
 
564
                return;
 
565
        }
 
566
 
 
567
        AST_LIST_LOCK(&reload_queue);
 
568
 
 
569
        if (do_full_reload) {
 
570
                do_full_reload = 0;
 
571
                AST_LIST_UNLOCK(&reload_queue);
 
572
                ast_log(LOG_NOTICE, "Executing deferred reload request.\n");
 
573
                ast_module_reload(NULL);
 
574
                return;
 
575
        }
 
576
 
 
577
        while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
 
578
                ast_log(LOG_NOTICE, "Executing deferred reload request for module '%s'.\n", item->module);
 
579
                ast_module_reload(item->module);
 
580
                ast_free(item);
 
581
        }
 
582
 
 
583
        AST_LIST_UNLOCK(&reload_queue);
 
584
}
 
585
 
 
586
static void queue_reload_request(const char *module)
 
587
{
 
588
        struct reload_queue_item *item;
 
589
 
 
590
        AST_LIST_LOCK(&reload_queue);
 
591
 
 
592
        if (do_full_reload) {
 
593
                AST_LIST_UNLOCK(&reload_queue);
 
594
                return;
 
595
        }
 
596
 
 
597
        if (ast_strlen_zero(module)) {
 
598
                /* A full reload request (when module is NULL) wipes out any previous
 
599
                   reload requests and causes the queue to ignore future ones */
 
600
                while ((item = AST_LIST_REMOVE_HEAD(&reload_queue, entry))) {
 
601
                        ast_free(item);
 
602
                }
 
603
                do_full_reload = 1;
 
604
        } else {
 
605
                /* No reason to add the same module twice */
 
606
                AST_LIST_TRAVERSE(&reload_queue, item, entry) {
 
607
                        if (!strcasecmp(item->module, module)) {
 
608
                                AST_LIST_UNLOCK(&reload_queue);
 
609
                                return;
 
610
                        }
 
611
                }
 
612
                item = ast_calloc(1, sizeof(*item) + strlen(module) + 1);
 
613
                if (!item) {
 
614
                        ast_log(LOG_ERROR, "Failed to allocate reload queue item.\n");
 
615
                        AST_LIST_UNLOCK(&reload_queue);
 
616
                        return;
 
617
                }
 
618
                strcpy(item->module, module);
 
619
                AST_LIST_INSERT_TAIL(&reload_queue, item, entry);
 
620
        }
 
621
        AST_LIST_UNLOCK(&reload_queue);
 
622
}
 
623
 
 
624
int ast_module_reload(const char *name)
 
625
{
 
626
        struct ast_module *cur;
 
627
        int res = 0; /* return value. 0 = not found, others, see below */
 
628
        int i;
 
629
 
 
630
        /* If we aren't fully booted, we just pretend we reloaded but we queue this
 
631
           up to run once we are booted up. */
 
632
        if (!ast_fully_booted) {
 
633
                queue_reload_request(name);
 
634
                return 0;
 
635
        }
 
636
 
 
637
        if (ast_mutex_trylock(&reloadlock)) {
 
638
                ast_verbose("The previous reload command didn't finish yet\n");
 
639
                return -1;      /* reload already in progress */
 
640
        }
 
641
        ast_lastreloadtime = ast_tvnow();
 
642
 
 
643
        /* Call "predefined" reload here first */
 
644
        for (i = 0; reload_classes[i].name; i++) {
 
645
                if (!name || !strcasecmp(name, reload_classes[i].name)) {
 
646
                        reload_classes[i].reload_fn();  /* XXX should check error ? */
 
647
                        res = 2;        /* found and reloaded */
 
648
                }
 
649
        }
 
650
 
 
651
        if (name && res) {
 
652
                ast_mutex_unlock(&reloadlock);
 
653
                return res;
 
654
        }
 
655
 
 
656
        AST_LIST_LOCK(&module_list);
 
657
        AST_LIST_TRAVERSE(&module_list, cur, entry) {
 
658
                const struct ast_module_info *info = cur->info;
 
659
 
 
660
                if (name && resource_name_match(name, cur->resource))
 
661
                        continue;
 
662
 
 
663
                if (!cur->flags.running || cur->flags.declined) {
 
664
                        if (!name)
 
665
                                continue;
 
666
                        ast_log(LOG_NOTICE, "The module '%s' was not properly initialized.  "
 
667
                                "Before reloading the module, you must run \"module load %s\" "
 
668
                                "and fix whatever is preventing the module from being initialized.\n",
 
669
                                name, name);
 
670
                        res = 2; /* Don't report that the module was not found */
 
671
                        break;
 
672
                }
 
673
 
 
674
                if (!info->reload) {    /* cannot be reloaded */
 
675
                        if (res < 1)    /* store result if possible */
 
676
                                res = 1;        /* 1 = no reload() method */
 
677
                        continue;
 
678
                }
 
679
 
 
680
                res = 2;
 
681
                ast_verb(3, "Reloading module '%s' (%s)\n", cur->resource, info->description);
 
682
                info->reload();
 
683
        }
 
684
        AST_LIST_UNLOCK(&module_list);
 
685
 
 
686
        ast_mutex_unlock(&reloadlock);
 
687
 
 
688
        return res;
 
689
}
 
690
 
 
691
static unsigned int inspect_module(const struct ast_module *mod)
 
692
{
 
693
        if (!mod->info->description) {
 
694
                ast_log(LOG_WARNING, "Module '%s' does not provide a description.\n", mod->resource);
 
695
                return 1;
 
696
        }
 
697
 
 
698
        if (!mod->info->key) {
 
699
                ast_log(LOG_WARNING, "Module '%s' does not provide a license key.\n", mod->resource);
 
700
                return 1;
 
701
        }
 
702
 
 
703
        if (verify_key((unsigned char *) mod->info->key)) {
 
704
                ast_log(LOG_WARNING, "Module '%s' did not provide a valid license key.\n", mod->resource);
 
705
                return 1;
 
706
        }
 
707
 
 
708
        if (!ast_strlen_zero(mod->info->buildopt_sum) &&
 
709
            strcmp(buildopt_sum, mod->info->buildopt_sum)) {
 
710
                ast_log(LOG_WARNING, "Module '%s' was not compiled with the same compile-time options as this version of Asterisk.\n", mod->resource);
 
711
                ast_log(LOG_WARNING, "Module '%s' will not be initialized as it may cause instability.\n", mod->resource);
 
712
                return 1;
 
713
        }
 
714
 
 
715
        return 0;
 
716
}
 
717
 
 
718
static enum ast_module_load_result start_resource(struct ast_module *mod)
 
719
{
 
720
        char tmp[256];
 
721
        enum ast_module_load_result res;
 
722
 
 
723
        if (!mod->info->load) {
 
724
                return AST_MODULE_LOAD_FAILURE;
 
725
        }
 
726
 
 
727
        res = mod->info->load();
 
728
 
 
729
        switch (res) {
 
730
        case AST_MODULE_LOAD_SUCCESS:
 
731
                if (!ast_fully_booted) {
 
732
                        ast_verb(1, "%s => (%s)\n", mod->resource, term_color(tmp, mod->info->description, COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
 
733
                        if (ast_opt_console && !option_verbose)
 
734
                                ast_verbose( ".");
 
735
                } else {
 
736
                        ast_verb(1, "Loaded %s => (%s)\n", mod->resource, mod->info->description);
 
737
                }
 
738
 
 
739
                mod->flags.running = 1;
 
740
 
 
741
                ast_update_use_count();
 
742
                break;
 
743
        case AST_MODULE_LOAD_DECLINE:
 
744
                mod->flags.declined = 1;
 
745
                break;
 
746
        case AST_MODULE_LOAD_FAILURE:
 
747
        case AST_MODULE_LOAD_SKIP: /* modules should never return this value */
 
748
        case AST_MODULE_LOAD_PRIORITY:
 
749
                break;
 
750
        }
 
751
 
 
752
        return res;
 
753
}
 
754
 
 
755
/*! loads a resource based upon resource_name. If global_symbols_only is set
 
756
 *  only modules with global symbols will be loaded.
 
757
 *
 
758
 *  If the ast_heap is provided (not NULL) the module is found and added to the
 
759
 *  heap without running the module's load() function.  By doing this, modules
 
760
 *  added to the resource_heap can be initialized later in order by priority. 
 
761
 *
 
762
 *  If the ast_heap is not provided, the module's load function will be executed
 
763
 *  immediately */
 
764
static enum ast_module_load_result load_resource(const char *resource_name, unsigned int global_symbols_only, struct ast_heap *resource_heap)
 
765
{
 
766
        struct ast_module *mod;
 
767
        enum ast_module_load_result res = AST_MODULE_LOAD_SUCCESS;
 
768
 
 
769
        if ((mod = find_resource(resource_name, 0))) {
 
770
                if (mod->flags.running) {
 
771
                        ast_log(LOG_WARNING, "Module '%s' already exists.\n", resource_name);
 
772
                        return AST_MODULE_LOAD_DECLINE;
 
773
                }
 
774
                if (global_symbols_only && !ast_test_flag(mod->info, AST_MODFLAG_GLOBAL_SYMBOLS))
 
775
                        return AST_MODULE_LOAD_SKIP;
 
776
        } else {
 
777
#ifdef LOADABLE_MODULES
 
778
                if (!(mod = load_dynamic_module(resource_name, global_symbols_only))) {
 
779
                        /* don't generate a warning message during load_modules() */
 
780
                        if (!global_symbols_only) {
 
781
                                ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
 
782
                                return AST_MODULE_LOAD_DECLINE;
 
783
                        } else {
 
784
                                return AST_MODULE_LOAD_SKIP;
 
785
                        }
 
786
                }
 
787
#else
 
788
                ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
 
789
                return AST_MODULE_LOAD_DECLINE;
 
790
#endif
 
791
        }
 
792
 
 
793
        if (inspect_module(mod)) {
 
794
                ast_log(LOG_WARNING, "Module '%s' could not be loaded.\n", resource_name);
 
795
#ifdef LOADABLE_MODULES
 
796
                unload_dynamic_module(mod);
 
797
#endif
 
798
                return AST_MODULE_LOAD_DECLINE;
 
799
        }
 
800
 
 
801
        if (!mod->lib && mod->info->backup_globals()) {
 
802
                ast_log(LOG_WARNING, "Module '%s' was unable to backup its global data.\n", resource_name);
 
803
                return AST_MODULE_LOAD_DECLINE;
 
804
        }
 
805
 
 
806
        mod->flags.declined = 0;
 
807
 
 
808
        if (resource_heap) {
 
809
                ast_heap_push(resource_heap, mod);
 
810
                res = AST_MODULE_LOAD_PRIORITY;
 
811
        } else {
 
812
                res = start_resource(mod);
 
813
        }
 
814
 
 
815
        return res;
 
816
}
 
817
 
 
818
int ast_load_resource(const char *resource_name)
 
819
{
 
820
        int res;
 
821
        AST_LIST_LOCK(&module_list);
 
822
        res = load_resource(resource_name, 0, NULL);
 
823
        AST_LIST_UNLOCK(&module_list);
 
824
 
 
825
        return res;
 
826
}
 
827
 
 
828
struct load_order_entry {
 
829
        char *resource;
 
830
        AST_LIST_ENTRY(load_order_entry) entry;
 
831
};
 
832
 
 
833
AST_LIST_HEAD_NOLOCK(load_order, load_order_entry);
 
834
 
 
835
static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order)
 
836
{
 
837
        struct load_order_entry *order;
 
838
 
 
839
        AST_LIST_TRAVERSE(load_order, order, entry) {
 
840
                if (!resource_name_match(order->resource, resource))
 
841
                        return NULL;
 
842
        }
 
843
 
 
844
        if (!(order = ast_calloc(1, sizeof(*order))))
 
845
                return NULL;
 
846
 
 
847
        order->resource = ast_strdup(resource);
 
848
        AST_LIST_INSERT_TAIL(load_order, order, entry);
 
849
 
 
850
        return order;
 
851
}
 
852
 
 
853
static int mod_load_cmp(void *a, void *b)
 
854
{
 
855
        struct ast_module *a_mod = (struct ast_module *) a;
 
856
        struct ast_module *b_mod = (struct ast_module *) b;
 
857
        int res = -1;
 
858
        /* if load_pri is not set, default is 255.  Lower is better*/
 
859
        unsigned char a_pri = ast_test_flag(a_mod->info, AST_MODFLAG_LOAD_ORDER) ? a_mod->info->load_pri : 255;
 
860
        unsigned char b_pri = ast_test_flag(b_mod->info, AST_MODFLAG_LOAD_ORDER) ? b_mod->info->load_pri : 255;
 
861
        if (a_pri == b_pri) {
 
862
                res = 0;
 
863
        } else if (a_pri < b_pri) {
 
864
                res = 1;
 
865
        }
 
866
        return res;
 
867
}
 
868
 
 
869
/*! loads modules in order by load_pri, updates mod_count */
 
870
static int load_resource_list(struct load_order *load_order, unsigned int global_symbols, int *mod_count)
 
871
{
 
872
        struct ast_heap *resource_heap;
 
873
        struct load_order_entry *order;
 
874
        struct ast_module *mod;
 
875
        int count = 0;
 
876
        int res = 0;
 
877
 
 
878
        if(!(resource_heap = ast_heap_create(8, mod_load_cmp, -1))) {
 
879
                return -1;
 
880
        }
 
881
 
 
882
        /* first, add find and add modules to heap */
 
883
        AST_LIST_TRAVERSE_SAFE_BEGIN(load_order, order, entry) {
 
884
                switch (load_resource(order->resource, global_symbols, resource_heap)) {
 
885
                case AST_MODULE_LOAD_SUCCESS:
 
886
                case AST_MODULE_LOAD_DECLINE:
 
887
                        AST_LIST_REMOVE_CURRENT(entry);
 
888
                        ast_free(order->resource);
 
889
                        ast_free(order);
 
890
                        break;
 
891
                case AST_MODULE_LOAD_FAILURE:
 
892
                        res = -1;
 
893
                        goto done;
 
894
                case AST_MODULE_LOAD_SKIP:
 
895
                        break;
 
896
                case AST_MODULE_LOAD_PRIORITY:
 
897
                        AST_LIST_REMOVE_CURRENT(entry);
 
898
                        break;
 
899
                }
 
900
        }
 
901
        AST_LIST_TRAVERSE_SAFE_END;
 
902
 
 
903
        /* second remove modules from heap sorted by priority */
 
904
        while ((mod = ast_heap_pop(resource_heap))) {
 
905
                switch (start_resource(mod)) {
 
906
                case AST_MODULE_LOAD_SUCCESS:
 
907
                        count++;
 
908
                case AST_MODULE_LOAD_DECLINE:
 
909
                        break;
 
910
                case AST_MODULE_LOAD_FAILURE:
 
911
                        res = -1;
 
912
                        goto done;
 
913
                case AST_MODULE_LOAD_SKIP:
 
914
                case AST_MODULE_LOAD_PRIORITY:
 
915
                        break;
 
916
                }
 
917
        }
 
918
 
 
919
done:
 
920
        if (mod_count) {
 
921
                *mod_count += count;
 
922
        }
 
923
        ast_heap_destroy(resource_heap);
 
924
 
 
925
        return res;
 
926
}
 
927
 
 
928
int load_modules(unsigned int preload_only)
 
929
{
 
930
        struct ast_config *cfg;
 
931
        struct ast_module *mod;
 
932
        struct load_order_entry *order;
 
933
        struct ast_variable *v;
 
934
        unsigned int load_count;
 
935
        struct load_order load_order;
 
936
        int res = 0;
 
937
        struct ast_flags config_flags = { 0 };
 
938
        int modulecount = 0;
 
939
 
 
940
#ifdef LOADABLE_MODULES
 
941
        struct dirent *dirent;
 
942
        DIR *dir;
 
943
#endif
 
944
 
 
945
        /* all embedded modules have registered themselves by now */
 
946
        embedding = 0;
 
947
 
 
948
        ast_verb(1, "Asterisk Dynamic Loader Starting:\n");
 
949
 
 
950
        AST_LIST_HEAD_INIT_NOLOCK(&load_order);
 
951
 
 
952
        AST_LIST_LOCK(&module_list);
 
953
 
 
954
        if (embedded_module_list.first) {
 
955
                module_list.first = embedded_module_list.first;
 
956
                module_list.last = embedded_module_list.last;
 
957
                embedded_module_list.first = NULL;
 
958
        }
 
959
 
 
960
        cfg = ast_config_load2(AST_MODULE_CONFIG, "" /* core, can't reload */, config_flags);
 
961
        if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
 
962
                ast_log(LOG_WARNING, "No '%s' found, no modules will be loaded.\n", AST_MODULE_CONFIG);
 
963
                goto done;
 
964
        }
 
965
 
 
966
        /* first, find all the modules we have been explicitly requested to load */
 
967
        for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
 
968
                if (!strcasecmp(v->name, preload_only ? "preload" : "load")) {
 
969
                        add_to_load_order(v->value, &load_order);
 
970
                }
 
971
        }
 
972
 
 
973
        /* check if 'autoload' is on */
 
974
        if (!preload_only && ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
 
975
                /* if so, first add all the embedded modules that are not already running to the load order */
 
976
                AST_LIST_TRAVERSE(&module_list, mod, entry) {
 
977
                        /* if it's not embedded, skip it */
 
978
                        if (mod->lib)
 
979
                                continue;
 
980
 
 
981
                        if (mod->flags.running)
 
982
                                continue;
 
983
 
 
984
                        order = add_to_load_order(mod->resource, &load_order);
 
985
                }
 
986
 
 
987
#ifdef LOADABLE_MODULES
 
988
                /* if we are allowed to load dynamic modules, scan the directory for
 
989
                   for all available modules and add them as well */
 
990
                if ((dir  = opendir(ast_config_AST_MODULE_DIR))) {
 
991
                        while ((dirent = readdir(dir))) {
 
992
                                int ld = strlen(dirent->d_name);
 
993
 
 
994
                                /* Must end in .so to load it.  */
 
995
 
 
996
                                if (ld < 4)
 
997
                                        continue;
 
998
 
 
999
                                if (strcasecmp(dirent->d_name + ld - 3, ".so"))
 
1000
                                        continue;
 
1001
 
 
1002
                                /* if there is already a module by this name in the module_list,
 
1003
                                   skip this file */
 
1004
                                if (find_resource(dirent->d_name, 0))
 
1005
                                        continue;
 
1006
 
 
1007
                                add_to_load_order(dirent->d_name, &load_order);
 
1008
                        }
 
1009
 
 
1010
                        closedir(dir);
 
1011
                } else {
 
1012
                        if (!ast_opt_quiet)
 
1013
                                ast_log(LOG_WARNING, "Unable to open modules directory '%s'.\n",
 
1014
                                        ast_config_AST_MODULE_DIR);
 
1015
                }
 
1016
#endif
 
1017
        }
 
1018
 
 
1019
        /* now scan the config for any modules we are prohibited from loading and
 
1020
           remove them from the load order */
 
1021
        for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
 
1022
                if (strcasecmp(v->name, "noload"))
 
1023
                        continue;
 
1024
 
 
1025
                AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) {
 
1026
                        if (!resource_name_match(order->resource, v->value)) {
 
1027
                                AST_LIST_REMOVE_CURRENT(entry);
 
1028
                                ast_free(order->resource);
 
1029
                                ast_free(order);
 
1030
                        }
 
1031
                }
 
1032
                AST_LIST_TRAVERSE_SAFE_END;
 
1033
        }
 
1034
 
 
1035
        /* we are done with the config now, all the information we need is in the
 
1036
           load_order list */
 
1037
        ast_config_destroy(cfg);
 
1038
 
 
1039
        load_count = 0;
 
1040
        AST_LIST_TRAVERSE(&load_order, order, entry)
 
1041
                load_count++;
 
1042
 
 
1043
        if (load_count)
 
1044
                ast_log(LOG_NOTICE, "%d modules will be loaded.\n", load_count);
 
1045
 
 
1046
        /* first, load only modules that provide global symbols */
 
1047
        if ((res = load_resource_list(&load_order, 1, &modulecount)) < 0) {
 
1048
                goto done;
 
1049
        }
 
1050
 
 
1051
        /* now load everything else */
 
1052
        if ((res = load_resource_list(&load_order, 0, &modulecount)) < 0) {
 
1053
                goto done;
 
1054
        }
 
1055
 
 
1056
done:
 
1057
        while ((order = AST_LIST_REMOVE_HEAD(&load_order, entry))) {
 
1058
                ast_free(order->resource);
 
1059
                ast_free(order);
 
1060
        }
 
1061
 
 
1062
        AST_LIST_UNLOCK(&module_list);
 
1063
        
 
1064
        /* Tell manager clients that are aggressive at logging in that we're done
 
1065
           loading modules. If there's a DNS problem in chan_sip, we might not
 
1066
           even reach this */
 
1067
        manager_event(EVENT_FLAG_SYSTEM, "ModuleLoadReport", "ModuleLoadStatus: Done\r\nModuleSelection: %s\r\nModuleCount: %d\r\n", preload_only ? "Preload" : "All", modulecount);
 
1068
        
 
1069
        return res;
 
1070
}
 
1071
 
 
1072
void ast_update_use_count(void)
 
1073
{
 
1074
        /* Notify any module monitors that the use count for a
 
1075
           resource has changed */
 
1076
        struct loadupdate *m;
 
1077
 
 
1078
        AST_LIST_LOCK(&updaters);
 
1079
        AST_LIST_TRAVERSE(&updaters, m, entry)
 
1080
                m->updater();
 
1081
        AST_LIST_UNLOCK(&updaters);
 
1082
}
 
1083
 
 
1084
int ast_update_module_list(int (*modentry)(const char *module, const char *description, int usecnt, const char *like),
 
1085
                           const char *like)
 
1086
{
 
1087
        struct ast_module *cur;
 
1088
        int unlock = -1;
 
1089
        int total_mod_loaded = 0;
 
1090
 
 
1091
        if (AST_LIST_TRYLOCK(&module_list))
 
1092
                unlock = 0;
 
1093
 
 
1094
        AST_LIST_TRAVERSE(&module_list, cur, entry) {
 
1095
                total_mod_loaded += modentry(cur->resource, cur->info->description, cur->usecount, like);
 
1096
        }
 
1097
 
 
1098
        if (unlock)
 
1099
                AST_LIST_UNLOCK(&module_list);
 
1100
 
 
1101
        return total_mod_loaded;
 
1102
}
 
1103
 
 
1104
/*! \brief Check if module exists */
 
1105
int ast_module_check(const char *name)
 
1106
{
 
1107
        struct ast_module *cur;
 
1108
 
 
1109
        if (ast_strlen_zero(name))
 
1110
                return 0;       /* FALSE */
 
1111
 
 
1112
        cur = find_resource(name, 1);
 
1113
 
 
1114
        return (cur != NULL);
 
1115
}
 
1116
 
 
1117
 
 
1118
int ast_loader_register(int (*v)(void))
 
1119
{
 
1120
        struct loadupdate *tmp;
 
1121
 
 
1122
        if (!(tmp = ast_malloc(sizeof(*tmp))))
 
1123
                return -1;
 
1124
 
 
1125
        tmp->updater = v;
 
1126
        AST_LIST_LOCK(&updaters);
 
1127
        AST_LIST_INSERT_HEAD(&updaters, tmp, entry);
 
1128
        AST_LIST_UNLOCK(&updaters);
 
1129
 
 
1130
        return 0;
 
1131
}
 
1132
 
 
1133
int ast_loader_unregister(int (*v)(void))
 
1134
{
 
1135
        struct loadupdate *cur;
 
1136
 
 
1137
        AST_LIST_LOCK(&updaters);
 
1138
        AST_LIST_TRAVERSE_SAFE_BEGIN(&updaters, cur, entry) {
 
1139
                if (cur->updater == v)  {
 
1140
                        AST_LIST_REMOVE_CURRENT(entry);
 
1141
                        break;
 
1142
                }
 
1143
        }
 
1144
        AST_LIST_TRAVERSE_SAFE_END;
 
1145
        AST_LIST_UNLOCK(&updaters);
 
1146
 
 
1147
        return cur ? 0 : -1;
 
1148
}
 
1149
 
 
1150
struct ast_module *ast_module_ref(struct ast_module *mod)
 
1151
{
 
1152
        ast_atomic_fetchadd_int(&mod->usecount, +1);
 
1153
        ast_update_use_count();
 
1154
 
 
1155
        return mod;
 
1156
}
 
1157
 
 
1158
void ast_module_unref(struct ast_module *mod)
 
1159
{
 
1160
        ast_atomic_fetchadd_int(&mod->usecount, -1);
 
1161
        ast_update_use_count();
 
1162
}