Merge in the bridge_construction branch to make the system use the Bridging API.
[asterisk/asterisk.git] / main / cli.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Standard Command Line Interface
22  *
23  * \author Mark Spencer <markster@digium.com>
24  */
25
26 /*! \li \ref cli.c uses the configuration file \ref cli_permissions.conf
27  * \addtogroup configuration_file Configuration Files
28  */
29
30 /*!
31  * \page cli_permissions.conf cli_permissions.conf
32  * \verbinclude cli_permissions.conf.sample
33  */
34
35 /*** MODULEINFO
36         <support_level>core</support_level>
37  ***/
38
39 #include "asterisk.h"
40
41 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
42
43 #include "asterisk/_private.h"
44 #include "asterisk/paths.h"     /* use ast_config_AST_MODULE_DIR */
45 #include <sys/signal.h>
46 #include <signal.h>
47 #include <ctype.h>
48 #include <regex.h>
49 #include <pwd.h>
50 #include <grp.h>
51 #include <editline/readline.h>
52
53 #include "asterisk/cli.h"
54 #include "asterisk/linkedlists.h"
55 #include "asterisk/module.h"
56 #include "asterisk/pbx.h"
57 #include "asterisk/channel.h"
58 #include "asterisk/utils.h"
59 #include "asterisk/app.h"
60 #include "asterisk/lock.h"
61 #include "asterisk/threadstorage.h"
62 #include "asterisk/translate.h"
63 #include "asterisk/bridging.h"
64
65 /*!
66  * \brief List of restrictions per user.
67  */
68 struct cli_perm {
69         unsigned int permit:1;                          /*!< 1=Permit 0=Deny */
70         char *command;                          /*!< Command name (to apply restrictions) */
71         AST_LIST_ENTRY(cli_perm) list;
72 };
73
74 AST_LIST_HEAD_NOLOCK(cli_perm_head, cli_perm);
75
76 /*! \brief list of users to apply restrictions. */
77 struct usergroup_cli_perm {
78         int uid;                                /*!< User ID (-1 disabled) */
79         int gid;                                /*!< Group ID (-1 disabled) */
80         struct cli_perm_head *perms;            /*!< List of permissions. */
81         AST_LIST_ENTRY(usergroup_cli_perm) list;/*!< List mechanics */
82 };
83 /*! \brief CLI permissions config file. */
84 static const char perms_config[] = "cli_permissions.conf";
85 /*! \brief Default permissions value 1=Permit 0=Deny */
86 static int cli_default_perm = 1;
87
88 /*! \brief mutex used to prevent a user from running the 'cli reload permissions' command while
89  * it is already running. */
90 AST_MUTEX_DEFINE_STATIC(permsconfiglock);
91 /*! \brief  List of users and permissions. */
92 static AST_RWLIST_HEAD_STATIC(cli_perms, usergroup_cli_perm);
93
94 /*!
95  * \brief map a debug or verbose level to a module name
96  */
97 struct module_level {
98         unsigned int level;
99         AST_RWLIST_ENTRY(module_level) entry;
100         char module[0];
101 };
102
103 AST_RWLIST_HEAD(module_level_list, module_level);
104
105 /*! list of module names and their debug levels */
106 static struct module_level_list debug_modules = AST_RWLIST_HEAD_INIT_VALUE;
107 /*! list of module names and their verbose levels */
108 static struct module_level_list verbose_modules = AST_RWLIST_HEAD_INIT_VALUE;
109
110 AST_THREADSTORAGE(ast_cli_buf);
111
112 /*! \brief Initial buffer size for resulting strings in ast_cli() */
113 #define AST_CLI_INITLEN   256
114
115 void ast_cli(int fd, const char *fmt, ...)
116 {
117         int res;
118         struct ast_str *buf;
119         va_list ap;
120
121         if (!(buf = ast_str_thread_get(&ast_cli_buf, AST_CLI_INITLEN)))
122                 return;
123
124         va_start(ap, fmt);
125         res = ast_str_set_va(&buf, 0, fmt, ap);
126         va_end(ap);
127
128         if (res != AST_DYNSTR_BUILD_FAILED) {
129                 ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
130         }
131 }
132
133 unsigned int ast_debug_get_by_module(const char *module)
134 {
135         struct module_level *ml;
136         unsigned int res = 0;
137
138         AST_RWLIST_RDLOCK(&debug_modules);
139         AST_LIST_TRAVERSE(&debug_modules, ml, entry) {
140                 if (!strcasecmp(ml->module, module)) {
141                         res = ml->level;
142                         break;
143                 }
144         }
145         AST_RWLIST_UNLOCK(&debug_modules);
146
147         return res;
148 }
149
150 unsigned int ast_verbose_get_by_module(const char *module)
151 {
152         struct module_level *ml;
153         unsigned int res = 0;
154
155         AST_RWLIST_RDLOCK(&verbose_modules);
156         AST_LIST_TRAVERSE(&verbose_modules, ml, entry) {
157                 if (!strcasecmp(ml->module, module)) {
158                         res = ml->level;
159                         break;
160                 }
161         }
162         AST_RWLIST_UNLOCK(&verbose_modules);
163
164         return res;
165 }
166
167 /*! \internal
168  *  \brief Check if the user with 'uid' and 'gid' is allow to execute 'command',
169  *         if command starts with '_' then not check permissions, just permit
170  *         to run the 'command'.
171  *         if uid == -1 or gid == -1 do not check permissions.
172  *         if uid == -2 and gid == -2 is because rasterisk client didn't send
173  *         the credentials, so the cli_default_perm will be applied.
174  *  \param uid User ID.
175  *  \param gid Group ID.
176  *  \param command Command name to check permissions.
177  *  \retval 1 if has permission
178  *  \retval 0 if it is not allowed.
179  */
180 static int cli_has_permissions(int uid, int gid, const char *command)
181 {
182         struct usergroup_cli_perm *user_perm;
183         struct cli_perm *perm;
184         /* set to the default permissions general option. */
185         int isallowg = cli_default_perm, isallowu = -1, ispattern;
186         regex_t regexbuf;
187
188         /* if uid == -1 or gid == -1 do not check permissions.
189            if uid == -2 and gid == -2 is because rasterisk client didn't send
190            the credentials, so the cli_default_perm will be applied. */
191         if ((uid == CLI_NO_PERMS && gid == CLI_NO_PERMS) || command[0] == '_') {
192                 return 1;
193         }
194
195         if (gid < 0 && uid < 0) {
196                 return cli_default_perm;
197         }
198
199         AST_RWLIST_RDLOCK(&cli_perms);
200         AST_LIST_TRAVERSE(&cli_perms, user_perm, list) {
201                 if (user_perm->gid != gid && user_perm->uid != uid) {
202                         continue;
203                 }
204                 AST_LIST_TRAVERSE(user_perm->perms, perm, list) {
205                         if (strcasecmp(perm->command, "all") && strncasecmp(perm->command, command, strlen(perm->command))) {
206                                 /* if the perm->command is a pattern, check it against command. */
207                                 ispattern = !regcomp(&regexbuf, perm->command, REG_EXTENDED | REG_NOSUB | REG_ICASE);
208                                 if (ispattern && regexec(&regexbuf, command, 0, NULL, 0)) {
209                                         regfree(&regexbuf);
210                                         continue;
211                                 }
212                                 if (!ispattern) {
213                                         continue;
214                                 }
215                                 regfree(&regexbuf);
216                         }
217                         if (user_perm->uid == uid) {
218                                 /* this is a user definition. */
219                                 isallowu = perm->permit;
220                         } else {
221                                 /* otherwise is a group definition. */
222                                 isallowg = perm->permit;
223                         }
224                 }
225         }
226         AST_RWLIST_UNLOCK(&cli_perms);
227         if (isallowu > -1) {
228                 /* user definition override group definition. */
229                 isallowg = isallowu;
230         }
231
232         return isallowg;
233 }
234
235 static AST_RWLIST_HEAD_STATIC(helpers, ast_cli_entry);
236
237 static char *complete_fn(const char *word, int state)
238 {
239         char *c, *d;
240         char filename[PATH_MAX];
241
242         if (word[0] == '/')
243                 ast_copy_string(filename, word, sizeof(filename));
244         else
245                 snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_MODULE_DIR, word);
246
247         c = d = filename_completion_function(filename, state);
248
249         if (c && word[0] != '/')
250                 c += (strlen(ast_config_AST_MODULE_DIR) + 1);
251         if (c)
252                 c = ast_strdup(c);
253
254         free(d);
255
256         return c;
257 }
258
259 static char *handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
260 {
261         /* "module load <mod>" */
262         switch (cmd) {
263         case CLI_INIT:
264                 e->command = "module load";
265                 e->usage =
266                         "Usage: module load <module name>\n"
267                         "       Loads the specified module into Asterisk.\n";
268                 return NULL;
269
270         case CLI_GENERATE:
271                 if (a->pos != e->args)
272                         return NULL;
273                 return complete_fn(a->word, a->n);
274         }
275         if (a->argc != e->args + 1)
276                 return CLI_SHOWUSAGE;
277         if (ast_load_resource(a->argv[e->args])) {
278                 ast_cli(a->fd, "Unable to load module %s\n", a->argv[e->args]);
279                 return CLI_FAILURE;
280         }
281         ast_cli(a->fd, "Loaded %s\n", a->argv[e->args]);
282         return CLI_SUCCESS;
283 }
284
285 static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
286 {
287         int x;
288
289         switch (cmd) {
290         case CLI_INIT:
291                 e->command = "module reload";
292                 e->usage =
293                         "Usage: module reload [module ...]\n"
294                         "       Reloads configuration files for all listed modules which support\n"
295                         "       reloading, or for all supported modules if none are listed.\n";
296                 return NULL;
297
298         case CLI_GENERATE:
299                 return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 1);
300         }
301         if (a->argc == e->args) {
302                 ast_module_reload(NULL);
303                 return CLI_SUCCESS;
304         }
305         for (x = e->args; x < a->argc; x++) {
306                 int res = ast_module_reload(a->argv[x]);
307                 /* XXX reload has multiple error returns, including -1 on error and 2 on success */
308                 switch (res) {
309                 case 0:
310                         ast_cli(a->fd, "No such module '%s'\n", a->argv[x]);
311                         break;
312                 case 1:
313                         ast_cli(a->fd, "Module '%s' does not support reload\n", a->argv[x]);
314                         break;
315                 }
316         }
317         return CLI_SUCCESS;
318 }
319
320 static char *handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
321 {
322         switch (cmd) {
323         case CLI_INIT:
324                 e->command = "core reload";
325                 e->usage =
326                         "Usage: core reload\n"
327                         "       Execute a global reload.\n";
328                 return NULL;
329
330         case CLI_GENERATE:
331                 return NULL;
332         }
333
334         if (a->argc != e->args) {
335                 return CLI_SHOWUSAGE;
336         }
337
338         ast_module_reload(NULL);
339
340         return CLI_SUCCESS;
341 }
342 /*!
343  * \brief Find the debug or verbose file setting
344  * \arg debug 1 for debug, 0 for verbose
345  */
346 static struct module_level *find_module_level(const char *module, unsigned int debug)
347 {
348         struct module_level *ml;
349         struct module_level_list *mll = debug ? &debug_modules : &verbose_modules;
350
351         AST_LIST_TRAVERSE(mll, ml, entry) {
352                 if (!strcasecmp(ml->module, module))
353                         return ml;
354         }
355
356         return NULL;
357 }
358
359 static char *complete_number(const char *partial, unsigned int min, unsigned int max, int n)
360 {
361         int i, count = 0;
362         unsigned int prospective[2];
363         unsigned int part = strtoul(partial, NULL, 10);
364         char next[12];
365
366         if (part < min || part > max) {
367                 return NULL;
368         }
369
370         for (i = 0; i < 21; i++) {
371                 if (i == 0) {
372                         prospective[0] = prospective[1] = part;
373                 } else if (part == 0 && !ast_strlen_zero(partial)) {
374                         break;
375                 } else if (i < 11) {
376                         prospective[0] = prospective[1] = part * 10 + (i - 1);
377                 } else {
378                         prospective[0] = (part * 10 + (i - 11)) * 10;
379                         prospective[1] = prospective[0] + 9;
380                 }
381                 if (i < 11 && (prospective[0] < min || prospective[0] > max)) {
382                         continue;
383                 } else if (prospective[1] < min || prospective[0] > max) {
384                         continue;
385                 }
386
387                 if (++count > n) {
388                         if (i < 11) {
389                                 snprintf(next, sizeof(next), "%u", prospective[0]);
390                         } else {
391                                 snprintf(next, sizeof(next), "%u...", prospective[0] / 10);
392                         }
393                         return ast_strdup(next);
394                 }
395         }
396         return NULL;
397 }
398
399 static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
400 {
401         int oldval;
402         int newlevel;
403         unsigned int is_debug;
404         int atleast = 0;
405         int fd = a->fd;
406         int argc = a->argc;
407         const char * const *argv = a->argv;
408         const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
409         int *dst;
410         char *what;
411         struct module_level_list *mll;
412         struct module_level *ml;
413
414         switch (cmd) {
415         case CLI_INIT:
416                 e->command = "core set {debug|verbose}";
417                 e->usage =
418 #if !defined(LOW_MEMORY)
419                         "Usage: core set {debug|verbose} [atleast] <level> [module]\n"
420 #else
421                         "Usage: core set {debug|verbose} [atleast] <level>\n"
422 #endif
423                         "       core set {debug|verbose} off\n"
424 #if !defined(LOW_MEMORY)
425                         "       Sets level of debug or verbose messages to be displayed or\n"
426                         "       sets a module name to display debug messages from.\n"
427 #else
428                         "       Sets level of debug or verbose messages to be displayed.\n"
429 #endif
430                         "       0 or off means no messages should be displayed.\n"
431                         "       Equivalent to -d[d[...]] or -v[v[v...]] on startup\n";
432                 return NULL;
433
434         case CLI_GENERATE:
435                 if (a->pos == 3 || (a->pos == 4 && !strcasecmp(a->argv[3], "atleast"))) {
436                         const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
437                         int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
438                         if (a->n < 21 && numbermatch == 0) {
439                                 return complete_number(pos, 0, 0x7fffffff, a->n);
440                         } else if (pos[0] == '0') {
441                                 if (a->n == 0) {
442                                         return ast_strdup("0");
443                                 } else {
444                                         return NULL;
445                                 }
446                         } else if (a->n == (21 - numbermatch)) {
447                                 if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
448                                         return ast_strdup("off");
449                                 } else if (a->pos == 3 && !strncasecmp(argv3, "atleast", strlen(argv3))) {
450                                         return ast_strdup("atleast");
451                                 }
452                         } else if (a->n == (22 - numbermatch) && a->pos == 3 && ast_strlen_zero(argv3)) {
453                                 return ast_strdup("atleast");
454                         }
455 #if !defined(LOW_MEMORY)
456                 } else if (a->pos == 4 || (a->pos == 5 && !strcasecmp(argv3, "atleast"))) {
457                         return ast_complete_source_filename(a->pos == 4 ? S_OR(a->argv[4], "") : S_OR(a->argv[5], ""), a->n);
458 #endif
459                 }
460                 return NULL;
461         }
462         /* all the above return, so we proceed with the handler.
463          * we are guaranteed to be called with argc >= e->args;
464          */
465
466         if (argc <= e->args)
467                 return CLI_SHOWUSAGE;
468         if (!strcasecmp(argv[e->args - 1], "debug")) {
469                 dst = &option_debug;
470                 oldval = option_debug;
471                 what = "Core debug";
472                 is_debug = 1;
473         } else {
474                 dst = &option_verbose;
475                 oldval = option_verbose;
476                 what = "Verbosity";
477                 is_debug = 0;
478         }
479         if (argc == e->args + 1 && !strcasecmp(argv[e->args], "off")) {
480                 newlevel = 0;
481
482                 mll = is_debug ? &debug_modules : &verbose_modules;
483
484                 AST_RWLIST_WRLOCK(mll);
485                 while ((ml = AST_RWLIST_REMOVE_HEAD(mll, entry))) {
486                         ast_free(ml);
487                 }
488                 ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
489                 AST_RWLIST_UNLOCK(mll);
490
491                 goto done;
492         }
493         if (!strcasecmp(argv[e->args], "atleast"))
494                 atleast = 1;
495         if (argc != e->args + atleast + 1 && argc != e->args + atleast + 2)
496                 return CLI_SHOWUSAGE;
497         if (sscanf(argv[e->args + atleast], "%30d", &newlevel) != 1)
498                 return CLI_SHOWUSAGE;
499         if (argc == e->args + atleast + 2) {
500                 /* We have specified a module name. */
501                 char *mod = ast_strdupa(argv[e->args + atleast + 1]);
502
503                 if ((strlen(mod) > 3) && !strcasecmp(mod + strlen(mod) - 3, ".so")) {
504                         mod[strlen(mod) - 3] = '\0';
505                 }
506
507                 mll = is_debug ? &debug_modules : &verbose_modules;
508
509                 AST_RWLIST_WRLOCK(mll);
510
511                 ml = find_module_level(mod, is_debug);
512                 if (!newlevel) {
513                         if (!ml) {
514                                 /* Specified off for a nonexistent entry. */
515                                 AST_RWLIST_UNLOCK(mll);
516                                 return CLI_SUCCESS;
517                         }
518                         AST_RWLIST_REMOVE(mll, ml, entry);
519                         if (AST_RWLIST_EMPTY(mll))
520                                 ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
521                         AST_RWLIST_UNLOCK(mll);
522                         ast_cli(fd, "%s was %d and has been set to 0 for '%s'\n", what, ml->level, mod);
523                         ast_free(ml);
524                         return CLI_SUCCESS;
525                 }
526
527                 if (ml) {
528                         if ((atleast && newlevel < ml->level) || ml->level == newlevel) {
529                                 ast_cli(fd, "%s is %d for '%s'\n", what, ml->level, mod);
530                                 AST_RWLIST_UNLOCK(mll);
531                                 return CLI_SUCCESS;
532                         }
533                         oldval = ml->level;
534                         ml->level = newlevel;
535                 } else {
536                         ml = ast_calloc(1, sizeof(*ml) + strlen(mod) + 1);
537                         if (!ml) {
538                                 AST_RWLIST_UNLOCK(mll);
539                                 return CLI_FAILURE;
540                         }
541                         oldval = ml->level;
542                         ml->level = newlevel;
543                         strcpy(ml->module, mod);
544                         AST_RWLIST_INSERT_TAIL(mll, ml, entry);
545                 }
546
547                 ast_set_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
548
549                 AST_RWLIST_UNLOCK(mll);
550
551                 ast_cli(fd, "%s was %d and has been set to %d for '%s'\n", what, oldval, ml->level, ml->module);
552
553                 return CLI_SUCCESS;
554         } else if (!newlevel) {
555                 /* Specified level as 0 instead of off. */
556                 mll = is_debug ? &debug_modules : &verbose_modules;
557
558                 AST_RWLIST_WRLOCK(mll);
559                 while ((ml = AST_RWLIST_REMOVE_HEAD(mll, entry))) {
560                         ast_free(ml);
561                 }
562                 ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
563                 AST_RWLIST_UNLOCK(mll);
564         }
565
566 done:
567         if (!atleast || newlevel > *dst)
568                 *dst = newlevel;
569         if (oldval > 0 && *dst == 0)
570                 ast_cli(fd, "%s is now OFF\n", what);
571         else if (*dst > 0) {
572                 if (oldval == *dst)
573                         ast_cli(fd, "%s is at least %d\n", what, *dst);
574                 else
575                         ast_cli(fd, "%s was %d and is now %d\n", what, oldval, *dst);
576         }
577
578         return CLI_SUCCESS;
579 }
580
581 static char *handle_logger_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
582 {
583         switch (cmd) {
584         case CLI_INIT:
585                 e->command = "logger mute";
586                 e->usage =
587                         "Usage: logger mute\n"
588                         "       Disables logging output to the current console, making it possible to\n"
589                         "       gather information without being disturbed by scrolling lines.\n";
590                 return NULL;
591         case CLI_GENERATE:
592                 return NULL;
593         }
594
595         if (a->argc < 2 || a->argc > 3)
596                 return CLI_SHOWUSAGE;
597
598         if (a->argc == 3 && !strcasecmp(a->argv[2], "silent"))
599                 ast_console_toggle_mute(a->fd, 1);
600         else
601                 ast_console_toggle_mute(a->fd, 0);
602
603         return CLI_SUCCESS;
604 }
605
606 static char *handle_unload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
607 {
608         /* "module unload mod_1 [mod_2 .. mod_N]" */
609         int x;
610         int force = AST_FORCE_SOFT;
611         const char *s;
612
613         switch (cmd) {
614         case CLI_INIT:
615                 e->command = "module unload";
616                 e->usage =
617                         "Usage: module unload [-f|-h] <module_1> [<module_2> ... ]\n"
618                         "       Unloads the specified module from Asterisk. The -f\n"
619                         "       option causes the module to be unloaded even if it is\n"
620                         "       in use (may cause a crash) and the -h module causes the\n"
621                         "       module to be unloaded even if the module says it cannot, \n"
622                         "       which almost always will cause a crash.\n";
623                 return NULL;
624
625         case CLI_GENERATE:
626                 return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0);
627         }
628         if (a->argc < e->args + 1)
629                 return CLI_SHOWUSAGE;
630         x = e->args;    /* first argument */
631         s = a->argv[x];
632         if (s[0] == '-') {
633                 if (s[1] == 'f')
634                         force = AST_FORCE_FIRM;
635                 else if (s[1] == 'h')
636                         force = AST_FORCE_HARD;
637                 else
638                         return CLI_SHOWUSAGE;
639                 if (a->argc < e->args + 2)      /* need at least one module name */
640                         return CLI_SHOWUSAGE;
641                 x++;    /* skip this argument */
642         }
643
644         for (; x < a->argc; x++) {
645                 if (ast_unload_resource(a->argv[x], force)) {
646                         ast_cli(a->fd, "Unable to unload resource %s\n", a->argv[x]);
647                         return CLI_FAILURE;
648                 }
649                 ast_cli(a->fd, "Unloaded %s\n", a->argv[x]);
650         }
651
652         return CLI_SUCCESS;
653 }
654
655 #define MODLIST_FORMAT  "%-30s %-40.40s %-10d %s\n"
656 #define MODLIST_FORMAT2 "%-30s %-40.40s %-10s %s\n"
657
658 AST_MUTEX_DEFINE_STATIC(climodentrylock);
659 static int climodentryfd = -1;
660
661 static int modlist_modentry(const char *module, const char *description, int usecnt, const char *status, const char *like)
662 {
663         /* Comparing the like with the module */
664         if (strcasestr(module, like) ) {
665                 ast_cli(climodentryfd, MODLIST_FORMAT, module, description, usecnt, status);
666                 return 1;
667         }
668         return 0;
669 }
670
671 static void print_uptimestr(int fd, struct timeval timeval, const char *prefix, int printsec)
672 {
673         int x; /* the main part - years, weeks, etc. */
674         struct ast_str *out;
675
676 #define SECOND (1)
677 #define MINUTE (SECOND*60)
678 #define HOUR (MINUTE*60)
679 #define DAY (HOUR*24)
680 #define WEEK (DAY*7)
681 #define YEAR (DAY*365)
682 #define NEEDCOMMA(x) ((x)? ",": "")     /* define if we need a comma */
683         if (timeval.tv_sec < 0) /* invalid, nothing to show */
684                 return;
685
686         if (printsec)  {        /* plain seconds output */
687                 ast_cli(fd, "%s: %lu\n", prefix, (u_long)timeval.tv_sec);
688                 return;
689         }
690         out = ast_str_alloca(256);
691         if (timeval.tv_sec > YEAR) {
692                 x = (timeval.tv_sec / YEAR);
693                 timeval.tv_sec -= (x * YEAR);
694                 ast_str_append(&out, 0, "%d year%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
695         }
696         if (timeval.tv_sec > WEEK) {
697                 x = (timeval.tv_sec / WEEK);
698                 timeval.tv_sec -= (x * WEEK);
699                 ast_str_append(&out, 0, "%d week%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
700         }
701         if (timeval.tv_sec > DAY) {
702                 x = (timeval.tv_sec / DAY);
703                 timeval.tv_sec -= (x * DAY);
704                 ast_str_append(&out, 0, "%d day%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
705         }
706         if (timeval.tv_sec > HOUR) {
707                 x = (timeval.tv_sec / HOUR);
708                 timeval.tv_sec -= (x * HOUR);
709                 ast_str_append(&out, 0, "%d hour%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
710         }
711         if (timeval.tv_sec > MINUTE) {
712                 x = (timeval.tv_sec / MINUTE);
713                 timeval.tv_sec -= (x * MINUTE);
714                 ast_str_append(&out, 0, "%d minute%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
715         }
716         x = timeval.tv_sec;
717         if (x > 0 || ast_str_strlen(out) == 0)  /* if there is nothing, print 0 seconds */
718                 ast_str_append(&out, 0, "%d second%s ", x, ESS(x));
719         ast_cli(fd, "%s: %s\n", prefix, ast_str_buffer(out));
720 }
721
722 static struct ast_cli_entry *cli_next(struct ast_cli_entry *e)
723 {
724         if (e) {
725                 return AST_LIST_NEXT(e, list);
726         } else {
727                 return AST_LIST_FIRST(&helpers);
728         }
729 }
730
731 static char * handle_showuptime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
732 {
733         struct timeval curtime = ast_tvnow();
734         int printsec;
735
736         switch (cmd) {
737         case CLI_INIT:
738                 e->command = "core show uptime [seconds]";
739                 e->usage =
740                         "Usage: core show uptime [seconds]\n"
741                         "       Shows Asterisk uptime information.\n"
742                         "       The seconds word returns the uptime in seconds only.\n";
743                 return NULL;
744
745         case CLI_GENERATE:
746                 return NULL;
747         }
748         /* regular handler */
749         if (a->argc == e->args && !strcasecmp(a->argv[e->args-1],"seconds"))
750                 printsec = 1;
751         else if (a->argc == e->args-1)
752                 printsec = 0;
753         else
754                 return CLI_SHOWUSAGE;
755         if (ast_startuptime.tv_sec)
756                 print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime", printsec);
757         if (ast_lastreloadtime.tv_sec)
758                 print_uptimestr(a->fd, ast_tvsub(curtime, ast_lastreloadtime), "Last reload", printsec);
759         return CLI_SUCCESS;
760 }
761
762 static char *handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
763 {
764         const char *like;
765
766         switch (cmd) {
767         case CLI_INIT:
768                 e->command = "module show [like]";
769                 e->usage =
770                         "Usage: module show [like keyword]\n"
771                         "       Shows Asterisk modules currently in use, and usage statistics.\n";
772                 return NULL;
773
774         case CLI_GENERATE:
775                 if (a->pos == e->args)
776                         return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0);
777                 else
778                         return NULL;
779         }
780         /* all the above return, so we proceed with the handler.
781          * we are guaranteed to have argc >= e->args
782          */
783         if (a->argc == e->args - 1)
784                 like = "";
785         else if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args-1], "like") )
786                 like = a->argv[e->args];
787         else
788                 return CLI_SHOWUSAGE;
789
790         ast_mutex_lock(&climodentrylock);
791         climodentryfd = a->fd; /* global, protected by climodentrylock */
792         ast_cli(a->fd, MODLIST_FORMAT2, "Module", "Description", "Use Count", "Status");
793         ast_cli(a->fd,"%d modules loaded\n", ast_update_module_list(modlist_modentry, like));
794         climodentryfd = -1;
795         ast_mutex_unlock(&climodentrylock);
796         return CLI_SUCCESS;
797 }
798 #undef MODLIST_FORMAT
799 #undef MODLIST_FORMAT2
800
801 static char *handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
802 {
803         struct timeval curtime = ast_tvnow();
804         int showuptime, printsec;
805
806         switch (cmd) {
807         case CLI_INIT:
808                 e->command = "core show calls [uptime]";
809                 e->usage =
810                         "Usage: core show calls [uptime] [seconds]\n"
811                         "       Lists number of currently active calls and total number of calls\n"
812                         "       processed through PBX since last restart. If 'uptime' is specified\n"
813                         "       the system uptime is also displayed. If 'seconds' is specified in\n"
814                         "       addition to 'uptime', the system uptime is displayed in seconds.\n";
815                 return NULL;
816
817         case CLI_GENERATE:
818                 if (a->pos != e->args)
819                         return NULL;
820                 return a->n == 0  ? ast_strdup("seconds") : NULL;
821         }
822
823         /* regular handler */
824         if (a->argc >= e->args && !strcasecmp(a->argv[e->args-1],"uptime")) {
825                 showuptime = 1;
826
827                 if (a->argc == e->args+1 && !strcasecmp(a->argv[e->args],"seconds"))
828                         printsec = 1;
829                 else if (a->argc == e->args)
830                         printsec = 0;
831                 else
832                         return CLI_SHOWUSAGE;
833         } else if (a->argc == e->args-1) {
834                 showuptime = 0;
835                 printsec = 0;
836         } else
837                 return CLI_SHOWUSAGE;
838
839         if (option_maxcalls) {
840                 ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
841                    ast_active_calls(), option_maxcalls, ESS(ast_active_calls()),
842                    ((double)ast_active_calls() / (double)option_maxcalls) * 100.0);
843         } else {
844                 ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
845         }
846
847         ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
848
849         if (ast_startuptime.tv_sec && showuptime) {
850                 print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime", printsec);
851         }
852
853         return RESULT_SUCCESS;
854 }
855
856 static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
857 {
858 #define FORMAT_STRING  "%-20.20s %-20.20s %-7.7s %-30.30s\n"
859 #define FORMAT_STRING2 "%-20.20s %-20.20s %-7.7s %-30.30s\n"
860 #define CONCISE_FORMAT_STRING  "%s!%s!%s!%d!%s!%s!%s!%s!%s!%s!%d!%s!%s!%s\n"
861 #define VERBOSE_FORMAT_STRING  "%-20.20s %-20.20s %-16.16s %4d %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n"
862 #define VERBOSE_FORMAT_STRING2 "%-20.20s %-20.20s %-16.16s %-4.4s %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n"
863
864         struct ast_channel *c = NULL;
865         int numchans = 0, concise = 0, verbose = 0, count = 0;
866         struct ast_channel_iterator *iter = NULL;
867
868         switch (cmd) {
869         case CLI_INIT:
870                 e->command = "core show channels [concise|verbose|count]";
871                 e->usage =
872                         "Usage: core show channels [concise|verbose|count]\n"
873                         "       Lists currently defined channels and some information about them. If\n"
874                         "       'concise' is specified, the format is abridged and in a more easily\n"
875                         "       machine parsable format. If 'verbose' is specified, the output includes\n"
876                         "       more and longer fields. If 'count' is specified only the channel and call\n"
877                         "       count is output.\n"
878                         "       The 'concise' option is deprecated and will be removed from future versions\n"
879                         "       of Asterisk.\n";
880                 return NULL;
881
882         case CLI_GENERATE:
883                 return NULL;
884         }
885
886         if (a->argc == e->args) {
887                 if (!strcasecmp(a->argv[e->args-1],"concise"))
888                         concise = 1;
889                 else if (!strcasecmp(a->argv[e->args-1],"verbose"))
890                         verbose = 1;
891                 else if (!strcasecmp(a->argv[e->args-1],"count"))
892                         count = 1;
893                 else
894                         return CLI_SHOWUSAGE;
895         } else if (a->argc != e->args - 1)
896                 return CLI_SHOWUSAGE;
897
898         if (!count) {
899                 if (!concise && !verbose)
900                         ast_cli(a->fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
901                 else if (verbose)
902                         ast_cli(a->fd, VERBOSE_FORMAT_STRING2, "Channel", "Context", "Extension", "Priority", "State", "Application", "Data",
903                                 "CallerID", "Duration", "Accountcode", "PeerAccount", "BridgeID");
904         }
905
906         if (!count && !(iter = ast_channel_iterator_all_new())) {
907                 return CLI_FAILURE;
908         }
909
910         for (; iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
911                 struct ast_bridge *bridge;
912                 char durbuf[10] = "-";
913
914                 ast_channel_lock(c);
915
916                 bridge = ast_channel_get_bridge(c);
917
918                 if (!count) {
919                         if ((concise || verbose)  && ast_channel_cdr(c) && !ast_tvzero(ast_channel_cdr(c)->start)) {
920                                 int duration = (int)(ast_tvdiff_ms(ast_tvnow(), ast_channel_cdr(c)->start) / 1000);
921                                 if (verbose) {
922                                         int durh = duration / 3600;
923                                         int durm = (duration % 3600) / 60;
924                                         int durs = duration % 60;
925                                         snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
926                                 } else {
927                                         snprintf(durbuf, sizeof(durbuf), "%d", duration);
928                                 }
929                         }
930                         if (concise) {
931                                 ast_cli(a->fd, CONCISE_FORMAT_STRING, ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_state2str(ast_channel_state(c)),
932                                         ast_channel_appl(c) ? ast_channel_appl(c) : "(None)",
933                                         S_OR(ast_channel_data(c), ""),  /* XXX different from verbose ? */
934                                         S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""),
935                                         S_OR(ast_channel_accountcode(c), ""),
936                                         S_OR(ast_channel_peeraccount(c), ""),
937                                         ast_channel_amaflags(c),
938                                         durbuf,
939                                         bridge ? bridge->uniqueid : "(Not bridged)",
940                                         ast_channel_uniqueid(c));
941                         } else if (verbose) {
942                                 ast_cli(a->fd, VERBOSE_FORMAT_STRING, ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), ast_state2str(ast_channel_state(c)),
943                                         ast_channel_appl(c) ? ast_channel_appl(c) : "(None)",
944                                         ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)" ): "(None)",
945                                         S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""),
946                                         durbuf,
947                                         S_OR(ast_channel_accountcode(c), ""),
948                                         S_OR(ast_channel_peeraccount(c), ""),
949                                         bridge ? bridge->uniqueid : "(Not bridged)");
950                         } else {
951                                 char locbuf[40] = "(None)";
952                                 char appdata[40] = "(None)";
953
954                                 if (!ast_strlen_zero(ast_channel_context(c)) && !ast_strlen_zero(ast_channel_exten(c)))
955                                         snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", ast_channel_exten(c), ast_channel_context(c), ast_channel_priority(c));
956                                 if (ast_channel_appl(c))
957                                         snprintf(appdata, sizeof(appdata), "%s(%s)", ast_channel_appl(c), S_OR(ast_channel_data(c), ""));
958                                 ast_cli(a->fd, FORMAT_STRING, ast_channel_name(c), locbuf, ast_state2str(ast_channel_state(c)), appdata);
959                         }
960                 }
961                 ast_channel_unlock(c);
962                 ao2_cleanup(bridge);
963         }
964
965         if (iter) {
966                 ast_channel_iterator_destroy(iter);
967         }
968
969         if (!concise) {
970                 numchans = ast_active_channels();
971                 ast_cli(a->fd, "%d active channel%s\n", numchans, ESS(numchans));
972                 if (option_maxcalls)
973                         ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
974                                 ast_active_calls(), option_maxcalls, ESS(ast_active_calls()),
975                                 ((double)ast_active_calls() / (double)option_maxcalls) * 100.0);
976                 else
977                         ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
978
979                 ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
980         }
981
982         return CLI_SUCCESS;
983
984 #undef FORMAT_STRING
985 #undef FORMAT_STRING2
986 #undef CONCISE_FORMAT_STRING
987 #undef VERBOSE_FORMAT_STRING
988 #undef VERBOSE_FORMAT_STRING2
989 }
990
991 static char *handle_softhangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
992 {
993         struct ast_channel *c=NULL;
994
995         switch (cmd) {
996         case CLI_INIT:
997                 e->command = "channel request hangup";
998                 e->usage =
999                         "Usage: channel request hangup <channel>|<all>\n"
1000                         "       Request that a channel be hung up. The hangup takes effect\n"
1001                         "       the next time the driver reads or writes from the channel.\n"
1002                         "       If 'all' is specified instead of a channel name, all channels\n"
1003                         "       will see the hangup request.\n";
1004                 return NULL;
1005         case CLI_GENERATE:
1006                 return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
1007         }
1008
1009         if (a->argc != 4) {
1010                 return CLI_SHOWUSAGE;
1011         }
1012
1013         if (!strcasecmp(a->argv[3], "all")) {
1014                 struct ast_channel_iterator *iter = NULL;
1015                 if (!(iter = ast_channel_iterator_all_new())) {
1016                         return CLI_FAILURE;
1017                 }
1018                 for (; iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
1019                         ast_channel_lock(c);
1020                         ast_cli(a->fd, "Requested Hangup on channel '%s'\n", ast_channel_name(c));
1021                         ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
1022                         ast_channel_unlock(c);
1023                 }
1024                 ast_channel_iterator_destroy(iter);
1025         } else if ((c = ast_channel_get_by_name(a->argv[3]))) {
1026                 ast_channel_lock(c);
1027                 ast_cli(a->fd, "Requested Hangup on channel '%s'\n", ast_channel_name(c));
1028                 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
1029                 ast_channel_unlock(c);
1030                 c = ast_channel_unref(c);
1031         } else {
1032                 ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
1033         }
1034
1035         return CLI_SUCCESS;
1036 }
1037
1038 /*! \brief handles CLI command 'cli show permissions' */
1039 static char *handle_cli_show_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1040 {
1041         struct usergroup_cli_perm *cp;
1042         struct cli_perm *perm;
1043         struct passwd *pw = NULL;
1044         struct group *gr = NULL;
1045
1046         switch (cmd) {
1047         case CLI_INIT:
1048                 e->command = "cli show permissions";
1049                 e->usage =
1050                         "Usage: cli show permissions\n"
1051                         "       Shows CLI configured permissions.\n";
1052                 return NULL;
1053         case CLI_GENERATE:
1054                 return NULL;
1055         }
1056
1057         AST_RWLIST_RDLOCK(&cli_perms);
1058         AST_LIST_TRAVERSE(&cli_perms, cp, list) {
1059                 if (cp->uid >= 0) {
1060                         pw = getpwuid(cp->uid);
1061                         if (pw) {
1062                                 ast_cli(a->fd, "user: %s [uid=%d]\n", pw->pw_name, cp->uid);
1063                         }
1064                 } else {
1065                         gr = getgrgid(cp->gid);
1066                         if (gr) {
1067                                 ast_cli(a->fd, "group: %s [gid=%d]\n", gr->gr_name, cp->gid);
1068                         }
1069                 }
1070                 ast_cli(a->fd, "Permissions:\n");
1071                 if (cp->perms) {
1072                         AST_LIST_TRAVERSE(cp->perms, perm, list) {
1073                                 ast_cli(a->fd, "\t%s -> %s\n", perm->permit ? "permit" : "deny", perm->command);
1074                         }
1075                 }
1076                 ast_cli(a->fd, "\n");
1077         }
1078         AST_RWLIST_UNLOCK(&cli_perms);
1079
1080         return CLI_SUCCESS;
1081 }
1082
1083 /*! \brief handles CLI command 'cli reload permissions' */
1084 static char *handle_cli_reload_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1085 {
1086         switch (cmd) {
1087         case CLI_INIT:
1088                 e->command = "cli reload permissions";
1089                 e->usage =
1090                         "Usage: cli reload permissions\n"
1091                         "       Reload the 'cli_permissions.conf' file.\n";
1092                 return NULL;
1093         case CLI_GENERATE:
1094                 return NULL;
1095         }
1096
1097         ast_cli_perms_init(1);
1098
1099         return CLI_SUCCESS;
1100 }
1101
1102 /*! \brief handles CLI command 'cli check permissions' */
1103 static char *handle_cli_check_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1104 {
1105         struct passwd *pw = NULL;
1106         struct group *gr;
1107         int gid = -1, uid = -1;
1108         char command[AST_MAX_ARGS] = "";
1109         struct ast_cli_entry *ce = NULL;
1110         int found = 0;
1111         char *group, *tmp;
1112
1113         switch (cmd) {
1114         case CLI_INIT:
1115                 e->command = "cli check permissions";
1116                 e->usage =
1117                         "Usage: cli check permissions {<username>|@<groupname>|<username>@<groupname>} [<command>]\n"
1118                         "       Check permissions config for a user@group or list the allowed commands for the specified user.\n"
1119                         "       The username or the groupname may be omitted.\n";
1120                 return NULL;
1121         case CLI_GENERATE:
1122                 if (a->pos >= 4) {
1123                         return ast_cli_generator(a->line + strlen("cli check permissions") + strlen(a->argv[3]) + 1, a->word, a->n);
1124                 }
1125                 return NULL;
1126         }
1127
1128         if (a->argc < 4) {
1129                 return CLI_SHOWUSAGE;
1130         }
1131
1132         tmp = ast_strdupa(a->argv[3]);
1133         group = strchr(tmp, '@');
1134         if (group) {
1135                 gr = getgrnam(&group[1]);
1136                 if (!gr) {
1137                         ast_cli(a->fd, "Unknown group '%s'\n", &group[1]);
1138                         return CLI_FAILURE;
1139                 }
1140                 group[0] = '\0';
1141                 gid = gr->gr_gid;
1142         }
1143
1144         if (!group && ast_strlen_zero(tmp)) {
1145                 ast_cli(a->fd, "You didn't supply a username\n");
1146         } else if (!ast_strlen_zero(tmp) && !(pw = getpwnam(tmp))) {
1147                 ast_cli(a->fd, "Unknown user '%s'\n", tmp);
1148                 return CLI_FAILURE;
1149         } else if (pw) {
1150                 uid = pw->pw_uid;
1151         }
1152
1153         if (a->argc == 4) {
1154                 while ((ce = cli_next(ce))) {
1155                         /* Hide commands that start with '_' */
1156                         if (ce->_full_cmd[0] == '_') {
1157                                 continue;
1158                         }
1159                         if (cli_has_permissions(uid, gid, ce->_full_cmd)) {
1160                                 ast_cli(a->fd, "%30.30s %s\n", ce->_full_cmd, S_OR(ce->summary, "<no description available>"));
1161                                 found++;
1162                         }
1163                 }
1164                 if (!found) {
1165                         ast_cli(a->fd, "You are not allowed to run any command on Asterisk\n");
1166                 }
1167         } else {
1168                 ast_join(command, sizeof(command), a->argv + 4);
1169                 ast_cli(a->fd, "%s '%s%s%s' is %s to run command: '%s'\n", uid >= 0 ? "User" : "Group", tmp,
1170                         group && uid >= 0 ? "@" : "",
1171                         group ? &group[1] : "",
1172                         cli_has_permissions(uid, gid, command) ? "allowed" : "not allowed", command);
1173         }
1174
1175         return CLI_SUCCESS;
1176 }
1177
1178 static char *__ast_cli_generator(const char *text, const char *word, int state, int lock);
1179
1180 static char *handle_commandmatchesarray(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1181 {
1182         char *buf, *obuf;
1183         int buflen = 2048;
1184         int len = 0;
1185         char **matches;
1186         int x, matchlen;
1187
1188         switch (cmd) {
1189         case CLI_INIT:
1190                 e->command = "_command matchesarray";
1191                 e->usage =
1192                         "Usage: _command matchesarray \"<line>\" text \n"
1193                         "       This function is used internally to help with command completion and should.\n"
1194                         "       never be called by the user directly.\n";
1195                 return NULL;
1196         case CLI_GENERATE:
1197                 return NULL;
1198         }
1199
1200         if (a->argc != 4)
1201                 return CLI_SHOWUSAGE;
1202         if (!(buf = ast_malloc(buflen)))
1203                 return CLI_FAILURE;
1204         buf[len] = '\0';
1205         matches = ast_cli_completion_matches(a->argv[2], a->argv[3]);
1206         if (matches) {
1207                 for (x=0; matches[x]; x++) {
1208                         matchlen = strlen(matches[x]) + 1;
1209                         if (len + matchlen >= buflen) {
1210                                 buflen += matchlen * 3;
1211                                 obuf = buf;
1212                                 if (!(buf = ast_realloc(obuf, buflen)))
1213                                         /* Memory allocation failure...  Just free old buffer and be done */
1214                                         ast_free(obuf);
1215                         }
1216                         if (buf)
1217                                 len += sprintf( buf + len, "%s ", matches[x]);
1218                         ast_free(matches[x]);
1219                         matches[x] = NULL;
1220                 }
1221                 ast_free(matches);
1222         }
1223
1224         if (buf) {
1225                 ast_cli(a->fd, "%s%s",buf, AST_CLI_COMPLETE_EOF);
1226                 ast_free(buf);
1227         } else
1228                 ast_cli(a->fd, "NULL\n");
1229
1230         return CLI_SUCCESS;
1231 }
1232
1233
1234
1235 static char *handle_commandnummatches(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1236 {
1237         int matches = 0;
1238
1239         switch (cmd) {
1240         case CLI_INIT:
1241                 e->command = "_command nummatches";
1242                 e->usage =
1243                         "Usage: _command nummatches \"<line>\" text \n"
1244                         "       This function is used internally to help with command completion and should.\n"
1245                         "       never be called by the user directly.\n";
1246                 return NULL;
1247         case CLI_GENERATE:
1248                 return NULL;
1249         }
1250
1251         if (a->argc != 4)
1252                 return CLI_SHOWUSAGE;
1253
1254         matches = ast_cli_generatornummatches(a->argv[2], a->argv[3]);
1255
1256         ast_cli(a->fd, "%d", matches);
1257
1258         return CLI_SUCCESS;
1259 }
1260
1261 static char *handle_commandcomplete(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1262 {
1263         char *buf;
1264         switch (cmd) {
1265         case CLI_INIT:
1266                 e->command = "_command complete";
1267                 e->usage =
1268                         "Usage: _command complete \"<line>\" text state\n"
1269                         "       This function is used internally to help with command completion and should.\n"
1270                         "       never be called by the user directly.\n";
1271                 return NULL;
1272         case CLI_GENERATE:
1273                 return NULL;
1274         }
1275         if (a->argc != 5)
1276                 return CLI_SHOWUSAGE;
1277         buf = __ast_cli_generator(a->argv[2], a->argv[3], atoi(a->argv[4]), 0);
1278         if (buf) {
1279                 ast_cli(a->fd, "%s", buf);
1280                 ast_free(buf);
1281         } else
1282                 ast_cli(a->fd, "NULL\n");
1283         return CLI_SUCCESS;
1284 }
1285
1286 struct channel_set_debug_args {
1287         int fd;
1288         int is_off;
1289 };
1290
1291 static int channel_set_debug(void *obj, void *arg, void *data, int flags)
1292 {
1293         struct ast_channel *chan = obj;
1294         struct channel_set_debug_args *args = data;
1295
1296         ast_channel_lock(chan);
1297
1298         if (!(ast_channel_fin(chan) & DEBUGCHAN_FLAG) || !(ast_channel_fout(chan) & DEBUGCHAN_FLAG)) {
1299                 if (args->is_off) {
1300                         ast_channel_fin_set(chan, ast_channel_fin(chan) & ~DEBUGCHAN_FLAG);
1301                         ast_channel_fout_set(chan, ast_channel_fout(chan) & ~DEBUGCHAN_FLAG);
1302                 } else {
1303                         ast_channel_fin_set(chan, ast_channel_fin(chan) | DEBUGCHAN_FLAG);
1304                         ast_channel_fout_set(chan, ast_channel_fout(chan) | DEBUGCHAN_FLAG);
1305                 }
1306                 ast_cli(args->fd, "Debugging %s on channel %s\n", args->is_off ? "disabled" : "enabled",
1307                                 ast_channel_name(chan));
1308         }
1309
1310         ast_channel_unlock(chan);
1311
1312         return 0;
1313 }
1314
1315 static char *handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1316 {
1317         struct ast_channel *c = NULL;
1318         struct channel_set_debug_args args = {
1319                 .fd = a->fd,
1320         };
1321
1322         switch (cmd) {
1323         case CLI_INIT:
1324                 e->command = "core set debug channel";
1325                 e->usage =
1326                         "Usage: core set debug channel <all|channel> [off]\n"
1327                         "       Enables/disables debugging on all or on a specific channel.\n";
1328                 return NULL;
1329         case CLI_GENERATE:
1330                 /* XXX remember to handle the optional "off" */
1331                 if (a->pos != e->args)
1332                         return NULL;
1333                 return a->n == 0 ? ast_strdup("all") : ast_complete_channels(a->line, a->word, a->pos, a->n - 1, e->args);
1334         }
1335
1336         if (cmd == (CLI_HANDLER + 1000)) {
1337                 /* called from handle_nodebugchan_deprecated */
1338                 args.is_off = 1;
1339         } else if (a->argc == e->args + 2) {
1340                 /* 'core set debug channel {all|chan_id}' */
1341                 if (!strcasecmp(a->argv[e->args + 1], "off"))
1342                         args.is_off = 1;
1343                 else
1344                         return CLI_SHOWUSAGE;
1345         } else if (a->argc != e->args + 1) {
1346                 return CLI_SHOWUSAGE;
1347         }
1348
1349         if (!strcasecmp("all", a->argv[e->args])) {
1350                 if (args.is_off) {
1351                         global_fin &= ~DEBUGCHAN_FLAG;
1352                         global_fout &= ~DEBUGCHAN_FLAG;
1353                 } else {
1354                         global_fin |= DEBUGCHAN_FLAG;
1355                         global_fout |= DEBUGCHAN_FLAG;
1356                 }
1357                 ast_channel_callback(channel_set_debug, NULL, &args, OBJ_NODATA | OBJ_MULTIPLE);
1358         } else {
1359                 if ((c = ast_channel_get_by_name(a->argv[e->args]))) {
1360                         channel_set_debug(c, NULL, &args, 0);
1361                         ast_channel_unref(c);
1362                 } else {
1363                         ast_cli(a->fd, "No such channel %s\n", a->argv[e->args]);
1364                 }
1365         }
1366
1367         ast_cli(a->fd, "Debugging on new channels is %s\n", args.is_off ? "disabled" : "enabled");
1368
1369         return CLI_SUCCESS;
1370 }
1371
1372 static char *handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1373 {
1374         char *res;
1375
1376         switch (cmd) {
1377         case CLI_INIT:
1378                 e->command = "no debug channel";
1379                 return NULL;
1380         case CLI_HANDLER:
1381                 /* exit out of switch statement */
1382                 break;
1383         default:
1384                 return NULL;
1385         }
1386
1387         if (a->argc != e->args + 1)
1388                 return CLI_SHOWUSAGE;
1389
1390         /* add a 'magic' value to the CLI_HANDLER command so that
1391          * handle_core_set_debug_channel() will act as if 'off'
1392          * had been specified as part of the command
1393          */
1394         res = handle_core_set_debug_channel(e, CLI_HANDLER + 1000, a);
1395
1396         return res;
1397 }
1398
1399 static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1400 {
1401         struct ast_channel *c=NULL;
1402         struct timeval now;
1403         char cdrtime[256];
1404         char nf[256];
1405         struct ast_str *write_transpath = ast_str_alloca(256);
1406         struct ast_str *read_transpath = ast_str_alloca(256);
1407         struct ast_str *obuf;/*!< Buffer for variable, CDR variable, and trace output. */
1408         struct ast_str *output;/*!< Accumulation buffer for all output. */
1409         long elapsed_seconds=0;
1410         int hour=0, min=0, sec=0;
1411         struct ast_callid *callid;
1412         char call_identifier_str[AST_CALLID_BUFFER_LENGTH] = "";
1413         struct ast_party_id effective_connected_id;
1414 #ifdef CHANNEL_TRACE
1415         int trace_enabled;
1416 #endif
1417         struct ast_bridge *bridge;
1418
1419         switch (cmd) {
1420         case CLI_INIT:
1421                 e->command = "core show channel";
1422                 e->usage =
1423                         "Usage: core show channel <channel>\n"
1424                         "       Shows lots of information about the specified channel.\n";
1425                 return NULL;
1426         case CLI_GENERATE:
1427                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
1428         }
1429
1430         if (a->argc != 4) {
1431                 return CLI_SHOWUSAGE;
1432         }
1433
1434         now = ast_tvnow();
1435
1436         if (!(c = ast_channel_get_by_name(a->argv[3]))) {
1437                 ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
1438                 return CLI_SUCCESS;
1439         }
1440
1441         obuf = ast_str_thread_get(&ast_str_thread_global_buf, 16);
1442         if (!obuf) {
1443                 return CLI_FAILURE;
1444         }
1445         output = ast_str_create(8192);
1446         if (!output) {
1447                 return CLI_FAILURE;
1448         }
1449
1450         ast_channel_lock(c);
1451
1452         if (ast_channel_cdr(c)) {
1453                 elapsed_seconds = now.tv_sec - ast_channel_cdr(c)->start.tv_sec;
1454                 hour = elapsed_seconds / 3600;
1455                 min = (elapsed_seconds % 3600) / 60;
1456                 sec = elapsed_seconds % 60;
1457                 snprintf(cdrtime, sizeof(cdrtime), "%dh%dm%ds", hour, min, sec);
1458         } else {
1459                 strcpy(cdrtime, "N/A");
1460         }
1461
1462         /* Construct the call identifier string based on the status of the channel's call identifier */
1463         if ((callid = ast_channel_callid(c))) {
1464                 ast_callid_strnprint(call_identifier_str, sizeof(call_identifier_str), callid);
1465                 ast_callid_unref(callid);
1466         }
1467
1468         effective_connected_id = ast_channel_connected_effective_id(c);
1469         bridge = ast_channel_get_bridge(c);
1470
1471         ast_str_append(&output, 0,
1472                 " -- General --\n"
1473                 "           Name: %s\n"
1474                 "           Type: %s\n"
1475                 "       UniqueID: %s\n"
1476                 "       LinkedID: %s\n"
1477                 "      Caller ID: %s\n"
1478                 " Caller ID Name: %s\n"
1479                 "Connected Line ID: %s\n"
1480                 "Connected Line ID Name: %s\n"
1481                 "Eff. Connected Line ID: %s\n"
1482                 "Eff. Connected Line ID Name: %s\n"
1483                 "    DNID Digits: %s\n"
1484                 "       Language: %s\n"
1485                 "          State: %s (%d)\n"
1486                 "          Rings: %d\n"
1487                 "  NativeFormats: %s\n"
1488                 "    WriteFormat: %s\n"
1489                 "     ReadFormat: %s\n"
1490                 " WriteTranscode: %s %s\n"
1491                 "  ReadTranscode: %s %s\n"
1492                 "1st File Descriptor: %d\n"
1493                 "      Frames in: %d%s\n"
1494                 "     Frames out: %d%s\n"
1495                 " Time to Hangup: %ld\n"
1496                 "   Elapsed Time: %s\n"
1497                 "      Bridge ID: %s\n"
1498                 " --   PBX   --\n"
1499                 "        Context: %s\n"
1500                 "      Extension: %s\n"
1501                 "       Priority: %d\n"
1502                 "     Call Group: %llu\n"
1503                 "   Pickup Group: %llu\n"
1504                 "    Application: %s\n"
1505                 "           Data: %s\n"
1506                 "    Blocking in: %s\n"
1507                 " Call Identifer: %s\n",
1508                 ast_channel_name(c),
1509                 ast_channel_tech(c)->type,
1510                 ast_channel_uniqueid(c),
1511                 ast_channel_linkedid(c),
1512                 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "(N/A)"),
1513                 S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "(N/A)"),
1514                 S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "(N/A)"),
1515                 S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "(N/A)"),
1516                 S_COR(effective_connected_id.number.valid, effective_connected_id.number.str, "(N/A)"),
1517                 S_COR(effective_connected_id.name.valid, effective_connected_id.name.str, "(N/A)"),
1518                 S_OR(ast_channel_dialed(c)->number.str, "(N/A)"),
1519                 ast_channel_language(c),
1520                 ast_state2str(ast_channel_state(c)),
1521                 ast_channel_state(c),
1522                 ast_channel_rings(c),
1523                 ast_getformatname_multiple(nf, sizeof(nf), ast_channel_nativeformats(c)),
1524                 ast_getformatname(ast_channel_writeformat(c)),
1525                 ast_getformatname(ast_channel_readformat(c)),
1526                 ast_channel_writetrans(c) ? "Yes" : "No",
1527                 ast_translate_path_to_str(ast_channel_writetrans(c), &write_transpath),
1528                 ast_channel_readtrans(c) ? "Yes" : "No",
1529                 ast_translate_path_to_str(ast_channel_readtrans(c), &read_transpath),
1530                 ast_channel_fd(c, 0),
1531                 ast_channel_fin(c) & ~DEBUGCHAN_FLAG,
1532                 (ast_channel_fin(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
1533                 ast_channel_fout(c) & ~DEBUGCHAN_FLAG,
1534                 (ast_channel_fout(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
1535                 (long) ast_channel_whentohangup(c)->tv_sec,
1536                 cdrtime,
1537                 bridge ? bridge->uniqueid : "(Not bridged)",
1538                 ast_channel_context(c),
1539                 ast_channel_exten(c),
1540                 ast_channel_priority(c),
1541                 ast_channel_callgroup(c),
1542                 ast_channel_pickupgroup(c),
1543                 (ast_channel_appl(c) ? ast_channel_appl(c) : "(N/A)" ),
1544                 (ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)") : "(None)"),
1545                 (ast_test_flag(ast_channel_flags(c), AST_FLAG_BLOCKING) ? ast_channel_blockproc(c) : "(Not Blocking)"),
1546                 S_OR(call_identifier_str, "(None)"));
1547
1548         if (pbx_builtin_serialize_variables(c, &obuf)) {
1549                 ast_str_append(&output, 0, "      Variables:\n%s\n", ast_str_buffer(obuf));
1550         }
1551
1552         if (ast_channel_cdr(c) && ast_cdr_serialize_variables(ast_channel_cdr(c), &obuf, '=', '\n', 1)) {
1553                 ast_str_append(&output, 0, "  CDR Variables:\n%s\n", ast_str_buffer(obuf));
1554         }
1555
1556 #ifdef CHANNEL_TRACE
1557         trace_enabled = ast_channel_trace_is_enabled(c);
1558         ast_str_append(&output, 0, "  Context Trace: %s\n",
1559                 trace_enabled ? "Enabled" : "Disabled");
1560         if (trace_enabled && ast_channel_trace_serialize(c, &obuf)) {
1561                 ast_str_append(&output, 0, "          Trace:\n%s\n", ast_str_buffer(obuf));
1562         }
1563 #endif
1564
1565         ast_channel_unlock(c);
1566         c = ast_channel_unref(c);
1567         ao2_cleanup(bridge);
1568
1569         ast_cli(a->fd, "%s", ast_str_buffer(output));
1570         ast_free(output);
1571         return CLI_SUCCESS;
1572 }
1573
1574 /*
1575  * helper function to generate CLI matches from a fixed set of values.
1576  * A NULL word is acceptable.
1577  */
1578 char *ast_cli_complete(const char *word, const char * const choices[], int state)
1579 {
1580         int i, which = 0, len;
1581         len = ast_strlen_zero(word) ? 0 : strlen(word);
1582
1583         for (i = 0; choices[i]; i++) {
1584                 if ((!len || !strncasecmp(word, choices[i], len)) && ++which > state)
1585                         return ast_strdup(choices[i]);
1586         }
1587         return NULL;
1588 }
1589
1590 char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
1591 {
1592         struct ast_channel *c = NULL;
1593         int which = 0;
1594         char notfound = '\0';
1595         char *ret = &notfound; /* so NULL can break the loop */
1596         struct ast_channel_iterator *iter;
1597
1598         if (pos != rpos) {
1599                 return NULL;
1600         }
1601
1602         if (ast_strlen_zero(word)) {
1603                 iter = ast_channel_iterator_all_new();
1604         } else {
1605                 iter = ast_channel_iterator_by_name_new(word, strlen(word));
1606         }
1607
1608         if (!iter) {
1609                 return NULL;
1610         }
1611
1612         while (ret == &notfound && (c = ast_channel_iterator_next(iter))) {
1613                 if (++which > state) {
1614                         ast_channel_lock(c);
1615                         ret = ast_strdup(ast_channel_name(c));
1616                         ast_channel_unlock(c);
1617                 }
1618                 ast_channel_unref(c);
1619         }
1620
1621         ast_channel_iterator_destroy(iter);
1622
1623         return ret == &notfound ? NULL : ret;
1624 }
1625
1626 static char *group_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1627 {
1628 #define FORMAT_STRING  "%-25s  %-20s  %-20s\n"
1629
1630         struct ast_group_info *gi = NULL;
1631         int numchans = 0;
1632         regex_t regexbuf;
1633         int havepattern = 0;
1634
1635         switch (cmd) {
1636         case CLI_INIT:
1637                 e->command = "group show channels";
1638                 e->usage =
1639                         "Usage: group show channels [pattern]\n"
1640                         "       Lists all currently active channels with channel group(s) specified.\n"
1641                         "       Optional regular expression pattern is matched to group names for each\n"
1642                         "       channel.\n";
1643                 return NULL;
1644         case CLI_GENERATE:
1645                 return NULL;
1646         }
1647
1648         if (a->argc < 3 || a->argc > 4)
1649                 return CLI_SHOWUSAGE;
1650
1651         if (a->argc == 4) {
1652                 if (regcomp(&regexbuf, a->argv[3], REG_EXTENDED | REG_NOSUB))
1653                         return CLI_SHOWUSAGE;
1654                 havepattern = 1;
1655         }
1656
1657         ast_cli(a->fd, FORMAT_STRING, "Channel", "Group", "Category");
1658
1659         ast_app_group_list_rdlock();
1660
1661         gi = ast_app_group_list_head();
1662         while (gi) {
1663                 if (!havepattern || !regexec(&regexbuf, gi->group, 0, NULL, 0)) {
1664                         ast_cli(a->fd, FORMAT_STRING, ast_channel_name(gi->chan), gi->group, (ast_strlen_zero(gi->category) ? "(default)" : gi->category));
1665                         numchans++;
1666                 }
1667                 gi = AST_LIST_NEXT(gi, group_list);
1668         }
1669
1670         ast_app_group_list_unlock();
1671
1672         if (havepattern)
1673                 regfree(&regexbuf);
1674
1675         ast_cli(a->fd, "%d active channel%s\n", numchans, ESS(numchans));
1676         return CLI_SUCCESS;
1677 #undef FORMAT_STRING
1678 }
1679
1680 static char *handle_cli_wait_fullybooted(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1681 {
1682         switch (cmd) {
1683         case CLI_INIT:
1684                 e->command = "core waitfullybooted";
1685                 e->usage =
1686                         "Usage: core waitfullybooted\n"
1687                         "       Wait until Asterisk has fully booted.\n";
1688                 return NULL;
1689         case CLI_GENERATE:
1690                 return NULL;
1691         }
1692
1693         while (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
1694                 usleep(100);
1695         }
1696
1697         ast_cli(a->fd, "Asterisk has fully booted.\n");
1698
1699         return CLI_SUCCESS;
1700 }
1701
1702 static char *handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
1703
1704 static struct ast_cli_entry cli_cli[] = {
1705         /* Deprecated, but preferred command is now consolidated (and already has a deprecated command for it). */
1706         AST_CLI_DEFINE(handle_commandcomplete, "Command complete"),
1707         AST_CLI_DEFINE(handle_commandnummatches, "Returns number of command matches"),
1708         AST_CLI_DEFINE(handle_commandmatchesarray, "Returns command matches array"),
1709
1710         AST_CLI_DEFINE(handle_nodebugchan_deprecated, "Disable debugging on channel(s)"),
1711
1712         AST_CLI_DEFINE(handle_chanlist, "Display information on channels"),
1713
1714         AST_CLI_DEFINE(handle_showcalls, "Display information on calls"),
1715
1716         AST_CLI_DEFINE(handle_showchan, "Display information on a specific channel"),
1717
1718         AST_CLI_DEFINE(handle_core_set_debug_channel, "Enable/disable debugging on a channel"),
1719
1720         AST_CLI_DEFINE(handle_verbose, "Set level of debug/verbose chattiness"),
1721
1722         AST_CLI_DEFINE(group_show_channels, "Display active channels with group(s)"),
1723
1724         AST_CLI_DEFINE(handle_help, "Display help list, or specific help on a command"),
1725
1726         AST_CLI_DEFINE(handle_logger_mute, "Toggle logging output to a console"),
1727
1728         AST_CLI_DEFINE(handle_modlist, "List modules and info"),
1729
1730         AST_CLI_DEFINE(handle_load, "Load a module by name"),
1731
1732         AST_CLI_DEFINE(handle_reload, "Reload configuration for a module"),
1733
1734         AST_CLI_DEFINE(handle_core_reload, "Global reload"),
1735
1736         AST_CLI_DEFINE(handle_unload, "Unload a module by name"),
1737
1738         AST_CLI_DEFINE(handle_showuptime, "Show uptime information"),
1739
1740         AST_CLI_DEFINE(handle_softhangup, "Request a hangup on a given channel"),
1741
1742         AST_CLI_DEFINE(handle_cli_reload_permissions, "Reload CLI permissions config"),
1743
1744         AST_CLI_DEFINE(handle_cli_show_permissions, "Show CLI permissions"),
1745
1746         AST_CLI_DEFINE(handle_cli_check_permissions, "Try a permissions config for a user"),
1747
1748         AST_CLI_DEFINE(handle_cli_wait_fullybooted, "Wait for Asterisk to be fully booted"),
1749 };
1750
1751 /*!
1752  * Some regexp characters in cli arguments are reserved and used as separators.
1753  */
1754 static const char cli_rsvd[] = "[]{}|*%";
1755
1756 /*!
1757  * initialize the _full_cmd string and related parameters,
1758  * return 0 on success, -1 on error.
1759  */
1760 static int set_full_cmd(struct ast_cli_entry *e)
1761 {
1762         int i;
1763         char buf[80];
1764
1765         ast_join(buf, sizeof(buf), e->cmda);
1766         e->_full_cmd = ast_strdup(buf);
1767         if (!e->_full_cmd) {
1768                 ast_log(LOG_WARNING, "-- cannot allocate <%s>\n", buf);
1769                 return -1;
1770         }
1771         e->cmdlen = strcspn(e->_full_cmd, cli_rsvd);
1772         for (i = 0; e->cmda[i]; i++)
1773                 ;
1774         e->args = i;
1775         return 0;
1776 }
1777
1778 /*! \brief cleanup (free) cli_perms linkedlist. */
1779 static void destroy_user_perms(void)
1780 {
1781         struct cli_perm *perm;
1782         struct usergroup_cli_perm *user_perm;
1783
1784         AST_RWLIST_WRLOCK(&cli_perms);
1785         while ((user_perm = AST_LIST_REMOVE_HEAD(&cli_perms, list))) {
1786                 while ((perm = AST_LIST_REMOVE_HEAD(user_perm->perms, list))) {
1787                         ast_free(perm->command);
1788                         ast_free(perm);
1789                 }
1790                 ast_free(user_perm);
1791         }
1792         AST_RWLIST_UNLOCK(&cli_perms);
1793 }
1794
1795 int ast_cli_perms_init(int reload)
1796 {
1797         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1798         struct ast_config *cfg;
1799         char *cat = NULL;
1800         struct ast_variable *v;
1801         struct usergroup_cli_perm *user_group, *cp_entry;
1802         struct cli_perm *perm = NULL;
1803         struct passwd *pw;
1804         struct group *gr;
1805
1806         if (ast_mutex_trylock(&permsconfiglock)) {
1807                 ast_log(LOG_NOTICE, "You must wait until last 'cli reload permissions' command finish\n");
1808                 return 1;
1809         }
1810
1811         cfg = ast_config_load2(perms_config, "" /* core, can't reload */, config_flags);
1812         if (!cfg) {
1813                 ast_mutex_unlock(&permsconfiglock);
1814                 return 1;
1815         } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1816                 ast_mutex_unlock(&permsconfiglock);
1817                 return 0;
1818         }
1819
1820         /* free current structures. */
1821         destroy_user_perms();
1822
1823         while ((cat = ast_category_browse(cfg, cat))) {
1824                 if (!strcasecmp(cat, "general")) {
1825                         /* General options */
1826                         for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
1827                                 if (!strcasecmp(v->name, "default_perm")) {
1828                                         cli_default_perm = (!strcasecmp(v->value, "permit")) ? 1: 0;
1829                                 }
1830                         }
1831                         continue;
1832                 }
1833
1834                 /* users or groups */
1835                 gr = NULL, pw = NULL;
1836                 if (cat[0] == '@') {
1837                         /* This is a group */
1838                         gr = getgrnam(&cat[1]);
1839                         if (!gr) {
1840                                 ast_log (LOG_WARNING, "Unknown group '%s'\n", &cat[1]);
1841                                 continue;
1842                         }
1843                 } else {
1844                         /* This is a user */
1845                         pw = getpwnam(cat);
1846                         if (!pw) {
1847                                 ast_log (LOG_WARNING, "Unknown user '%s'\n", cat);
1848                                 continue;
1849                         }
1850                 }
1851                 user_group = NULL;
1852                 /* Check for duplicates */
1853                 AST_RWLIST_WRLOCK(&cli_perms);
1854                 AST_LIST_TRAVERSE(&cli_perms, cp_entry, list) {
1855                         if ((pw && cp_entry->uid == pw->pw_uid) || (gr && cp_entry->gid == gr->gr_gid)) {
1856                                 /* if it is duplicated, just added this new settings, to
1857                                 the current list. */
1858                                 user_group = cp_entry;
1859                                 break;
1860                         }
1861                 }
1862                 AST_RWLIST_UNLOCK(&cli_perms);
1863
1864                 if (!user_group) {
1865                         /* alloc space for the new user config. */
1866                         user_group = ast_calloc(1, sizeof(*user_group));
1867                         if (!user_group) {
1868                                 continue;
1869                         }
1870                         user_group->uid = (pw ? pw->pw_uid : -1);
1871                         user_group->gid = (gr ? gr->gr_gid : -1);
1872                         user_group->perms = ast_calloc(1, sizeof(*user_group->perms));
1873                         if (!user_group->perms) {
1874                                 ast_free(user_group);
1875                                 continue;
1876                         }
1877                 }
1878                 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
1879                         if (ast_strlen_zero(v->value)) {
1880                                 /* we need to check this condition cause it could break security. */
1881                                 ast_log(LOG_WARNING, "Empty permit/deny option in user '%s'\n", cat);
1882                                 continue;
1883                         }
1884                         if (!strcasecmp(v->name, "permit")) {
1885                                 perm = ast_calloc(1, sizeof(*perm));
1886                                 if (perm) {
1887                                         perm->permit = 1;
1888                                         perm->command = ast_strdup(v->value);
1889                                 }
1890                         } else if (!strcasecmp(v->name, "deny")) {
1891                                 perm = ast_calloc(1, sizeof(*perm));
1892                                 if (perm) {
1893                                         perm->permit = 0;
1894                                         perm->command = ast_strdup(v->value);
1895                                 }
1896                         } else {
1897                                 /* up to now, only 'permit' and 'deny' are possible values. */
1898                                 ast_log(LOG_WARNING, "Unknown '%s' option\n", v->name);
1899                                 continue;
1900                         }
1901                         if (perm) {
1902                                 /* Added the permission to the user's list. */
1903                                 AST_LIST_INSERT_TAIL(user_group->perms, perm, list);
1904                                 perm = NULL;
1905                         }
1906                 }
1907                 AST_RWLIST_WRLOCK(&cli_perms);
1908                 AST_RWLIST_INSERT_TAIL(&cli_perms, user_group, list);
1909                 AST_RWLIST_UNLOCK(&cli_perms);
1910         }
1911
1912         ast_config_destroy(cfg);
1913         ast_mutex_unlock(&permsconfiglock);
1914         return 0;
1915 }
1916
1917 static void cli_shutdown(void)
1918 {
1919         ast_cli_unregister_multiple(cli_cli, ARRAY_LEN(cli_cli));
1920 }
1921
1922 /*! \brief initialize the _full_cmd string in * each of the builtins. */
1923 void ast_builtins_init(void)
1924 {
1925         ast_cli_register_multiple(cli_cli, ARRAY_LEN(cli_cli));
1926         ast_register_atexit(cli_shutdown);
1927 }
1928
1929 /*!
1930  * match a word in the CLI entry.
1931  * returns -1 on mismatch, 0 on match of an optional word,
1932  * 1 on match of a full word.
1933  *
1934  * The pattern can be
1935  *   any_word           match for equal
1936  *   [foo|bar|baz]      optionally, one of these words
1937  *   {foo|bar|baz}      exactly, one of these words
1938  *   %                  any word
1939  */
1940 static int word_match(const char *cmd, const char *cli_word)
1941 {
1942         int l;
1943         char *pos;
1944
1945         if (ast_strlen_zero(cmd) || ast_strlen_zero(cli_word))
1946                 return -1;
1947         if (!strchr(cli_rsvd, cli_word[0])) /* normal match */
1948                 return (strcasecmp(cmd, cli_word) == 0) ? 1 : -1;
1949         l = strlen(cmd);
1950         /* wildcard match - will extend in the future */
1951         if (l > 0 && cli_word[0] == '%') {
1952                 return 1;       /* wildcard */
1953         }
1954
1955         /* Start a search for the command entered against the cli word in question */
1956         pos = strcasestr(cli_word, cmd);
1957         while (pos) {
1958
1959                 /*
1960                  *Check if the word matched with is surrounded by reserved characters on both sides
1961                  * and isn't at the beginning of the cli_word since that would make it check in a location we shouldn't know about.
1962                  * If it is surrounded by reserved chars and isn't at the beginning, it's a match.
1963                  */
1964                 if (pos != cli_word && strchr(cli_rsvd, pos[-1]) && strchr(cli_rsvd, pos[l])) {
1965                         return 1;       /* valid match */
1966                 }
1967
1968                 /* Ok, that one didn't match, strcasestr to the next appearance of the command and start over.*/
1969                 pos = strcasestr(pos + 1, cmd);
1970         }
1971         /* If no matches were found over the course of the while loop, we hit the end of the string. It's a mismatch. */
1972         return -1;
1973 }
1974
1975 /*! \brief if word is a valid prefix for token, returns the pos-th
1976  * match as a malloced string, or NULL otherwise.
1977  * Always tell in *actual how many matches we got.
1978  */
1979 static char *is_prefix(const char *word, const char *token,
1980         int pos, int *actual)
1981 {
1982         int lw;
1983         char *s, *t1;
1984
1985         *actual = 0;
1986         if (ast_strlen_zero(token))
1987                 return NULL;
1988         if (ast_strlen_zero(word))
1989                 word = "";      /* dummy */
1990         lw = strlen(word);
1991         if (strcspn(word, cli_rsvd) != lw)
1992                 return NULL;    /* no match if word has reserved chars */
1993         if (strchr(cli_rsvd, token[0]) == NULL) {       /* regular match */
1994                 if (strncasecmp(token, word, lw))       /* no match */
1995                         return NULL;
1996                 *actual = 1;
1997                 return (pos != 0) ? NULL : ast_strdup(token);
1998         }
1999         /* now handle regexp match */
2000
2001         /* Wildcard always matches, so we never do is_prefix on them */
2002
2003         t1 = ast_strdupa(token + 1);    /* copy, skipping first char */
2004         while (pos >= 0 && (s = strsep(&t1, cli_rsvd)) && *s) {
2005                 if (*s == '%')  /* wildcard */
2006                         continue;
2007                 if (strncasecmp(s, word, lw))   /* no match */
2008                         continue;
2009                 (*actual)++;
2010                 if (pos-- == 0)
2011                         return ast_strdup(s);
2012         }
2013         return NULL;
2014 }
2015
2016 /*!
2017  * \internal
2018  * \brief locate a cli command in the 'helpers' list (which must be locked).
2019  *     The search compares word by word taking care of regexps in e->cmda
2020  *     This function will return NULL when nothing is matched, or the ast_cli_entry that matched.
2021  * \param cmds
2022  * \param match_type has 3 possible values:
2023  *      0       returns if the search key is equal or longer than the entry.
2024  *                          note that trailing optional arguments are skipped.
2025  *      -1      true if the mismatch is on the last word XXX not true!
2026  *      1       true only on complete, exact match.
2027  *
2028  */
2029 static struct ast_cli_entry *find_cli(const char * const cmds[], int match_type)
2030 {
2031         int matchlen = -1;      /* length of longest match so far */
2032         struct ast_cli_entry *cand = NULL, *e=NULL;
2033
2034         while ( (e = cli_next(e)) ) {
2035                 /* word-by word regexp comparison */
2036                 const char * const *src = cmds;
2037                 const char * const *dst = e->cmda;
2038                 int n = 0;
2039                 for (;; dst++, src += n) {
2040                         n = word_match(*src, *dst);
2041                         if (n < 0)
2042                                 break;
2043                 }
2044                 if (ast_strlen_zero(*dst) || ((*dst)[0] == '[' && ast_strlen_zero(dst[1]))) {
2045                         /* no more words in 'e' */
2046                         if (ast_strlen_zero(*src))      /* exact match, cannot do better */
2047                                 break;
2048                         /* Here, cmds has more words than the entry 'e' */
2049                         if (match_type != 0)    /* but we look for almost exact match... */
2050                                 continue;       /* so we skip this one. */
2051                         /* otherwise we like it (case 0) */
2052                 } else {        /* still words in 'e' */
2053                         if (ast_strlen_zero(*src))
2054                                 continue; /* cmds is shorter than 'e', not good */
2055                         /* Here we have leftover words in cmds and 'e',
2056                          * but there is a mismatch. We only accept this one if match_type == -1
2057                          * and this is the last word for both.
2058                          */
2059                         if (match_type != -1 || !ast_strlen_zero(src[1]) ||
2060                             !ast_strlen_zero(dst[1]))   /* not the one we look for */
2061                                 continue;
2062                         /* good, we are in case match_type == -1 and mismatch on last word */
2063                 }
2064                 if (src - cmds > matchlen) {    /* remember the candidate */
2065                         matchlen = src - cmds;
2066                         cand = e;
2067                 }
2068         }
2069
2070         return e ? e : cand;
2071 }
2072
2073 static char *find_best(const char *argv[])
2074 {
2075         static char cmdline[80];
2076         int x;
2077         /* See how close we get, then print the candidate */
2078         const char *myargv[AST_MAX_CMD_LEN] = { NULL, };
2079
2080         AST_RWLIST_RDLOCK(&helpers);
2081         for (x = 0; argv[x]; x++) {
2082                 myargv[x] = argv[x];
2083                 if (!find_cli(myargv, -1))
2084                         break;
2085         }
2086         AST_RWLIST_UNLOCK(&helpers);
2087         ast_join(cmdline, sizeof(cmdline), myargv);
2088         return cmdline;
2089 }
2090
2091 static int cli_is_registered(struct ast_cli_entry *e)
2092 {
2093         struct ast_cli_entry *cur = NULL;
2094
2095         while ((cur = cli_next(cur))) {
2096                 if (cur == e) {
2097                         return 1;
2098                 }
2099         }
2100         return 0;
2101 }
2102
2103 static int __ast_cli_unregister(struct ast_cli_entry *e, struct ast_cli_entry *ed)
2104 {
2105         if (e->inuse) {
2106                 ast_log(LOG_WARNING, "Can't remove command that is in use\n");
2107         } else {
2108                 AST_RWLIST_WRLOCK(&helpers);
2109                 AST_RWLIST_REMOVE(&helpers, e, list);
2110                 AST_RWLIST_UNLOCK(&helpers);
2111                 ast_free(e->_full_cmd);
2112                 e->_full_cmd = NULL;
2113                 if (e->handler) {
2114                         /* this is a new-style entry. Reset fields and free memory. */
2115                         char *cmda = (char *) e->cmda;
2116                         memset(cmda, '\0', sizeof(e->cmda));
2117                         ast_free(e->command);
2118                         e->command = NULL;
2119                         e->usage = NULL;
2120                 }
2121         }
2122         return 0;
2123 }
2124
2125 static int __ast_cli_register(struct ast_cli_entry *e, struct ast_cli_entry *ed)
2126 {
2127         struct ast_cli_entry *cur;
2128         int i, lf, ret = -1;
2129
2130         struct ast_cli_args a;  /* fake argument */
2131         char **dst = (char **)e->cmda;  /* need to cast as the entry is readonly */
2132         char *s;
2133
2134         AST_RWLIST_WRLOCK(&helpers);
2135
2136         if (cli_is_registered(e)) {
2137                 ast_log(LOG_WARNING, "Command '%s' already registered (the same ast_cli_entry)\n",
2138                         S_OR(e->_full_cmd, e->command));
2139                 ret = 0;  /* report success */
2140                 goto done;
2141         }
2142
2143         memset(&a, '\0', sizeof(a));
2144         e->handler(e, CLI_INIT, &a);
2145         /* XXX check that usage and command are filled up */
2146         s = ast_skip_blanks(e->command);
2147         s = e->command = ast_strdup(s);
2148         for (i=0; !ast_strlen_zero(s) && i < AST_MAX_CMD_LEN-1; i++) {
2149                 *dst++ = s;     /* store string */
2150                 s = ast_skip_nonblanks(s);
2151                 if (*s == '\0') /* we are done */
2152                         break;
2153                 *s++ = '\0';
2154                 s = ast_skip_blanks(s);
2155         }
2156         *dst++ = NULL;
2157
2158         if (find_cli(e->cmda, 1)) {
2159                 ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n",
2160                         S_OR(e->_full_cmd, e->command));
2161                 goto done;
2162         }
2163         if (set_full_cmd(e)) {
2164                 ast_log(LOG_WARNING, "Error registering CLI Command '%s'\n",
2165                         S_OR(e->_full_cmd, e->command));
2166                 goto done;
2167         }
2168
2169         lf = e->cmdlen;
2170         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&helpers, cur, list) {
2171                 int len = cur->cmdlen;
2172                 if (lf < len)
2173                         len = lf;
2174                 if (strncasecmp(e->_full_cmd, cur->_full_cmd, len) < 0) {
2175                         AST_RWLIST_INSERT_BEFORE_CURRENT(e, list);
2176                         break;
2177                 }
2178         }
2179         AST_RWLIST_TRAVERSE_SAFE_END;
2180
2181         if (!cur)
2182                 AST_RWLIST_INSERT_TAIL(&helpers, e, list);
2183         ret = 0;        /* success */
2184
2185 done:
2186         AST_RWLIST_UNLOCK(&helpers);
2187         if (ret) {
2188                 ast_free(e->command);
2189                 e->command = NULL;
2190         }
2191
2192         return ret;
2193 }
2194
2195 /* wrapper function, so we can unregister deprecated commands recursively */
2196 int ast_cli_unregister(struct ast_cli_entry *e)
2197 {
2198         return __ast_cli_unregister(e, NULL);
2199 }
2200
2201 /* wrapper function, so we can register deprecated commands recursively */
2202 int ast_cli_register(struct ast_cli_entry *e)
2203 {
2204         return __ast_cli_register(e, NULL);
2205 }
2206
2207 /*
2208  * register/unregister an array of entries.
2209  */
2210 int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
2211 {
2212         int i, res = 0;
2213
2214         for (i = 0; i < len; i++)
2215                 res |= ast_cli_register(e + i);
2216
2217         return res;
2218 }
2219
2220 int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
2221 {
2222         int i, res = 0;
2223
2224         for (i = 0; i < len; i++)
2225                 res |= ast_cli_unregister(e + i);
2226
2227         return res;
2228 }
2229
2230
2231 /*! \brief helper for final part of handle_help
2232  *  if locked = 1, assume the list is already locked
2233  */
2234 static char *help1(int fd, const char * const match[], int locked)
2235 {
2236         char matchstr[80] = "";
2237         struct ast_cli_entry *e = NULL;
2238         int len = 0;
2239         int found = 0;
2240
2241         if (match) {
2242                 ast_join(matchstr, sizeof(matchstr), match);
2243                 len = strlen(matchstr);
2244         }
2245         if (!locked)
2246                 AST_RWLIST_RDLOCK(&helpers);
2247         while ( (e = cli_next(e)) ) {
2248                 /* Hide commands that start with '_' */
2249                 if (e->_full_cmd[0] == '_')
2250                         continue;
2251                 if (match && strncasecmp(matchstr, e->_full_cmd, len))
2252                         continue;
2253                 ast_cli(fd, "%-30s -- %s\n", e->_full_cmd,
2254                         S_OR(e->summary, "<no description available>"));
2255                 found++;
2256         }
2257         if (!locked)
2258                 AST_RWLIST_UNLOCK(&helpers);
2259         if (!found && matchstr[0])
2260                 ast_cli(fd, "No such command '%s'.\n", matchstr);
2261         return CLI_SUCCESS;
2262 }
2263
2264 static char *handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2265 {
2266         char fullcmd[80];
2267         struct ast_cli_entry *my_e;
2268         char *res = CLI_SUCCESS;
2269
2270         if (cmd == CLI_INIT) {
2271                 e->command = "core show help";
2272                 e->usage =
2273                         "Usage: core show help [topic]\n"
2274                         "       When called with a topic as an argument, displays usage\n"
2275                         "       information on the given command. If called without a\n"
2276                         "       topic, it provides a list of commands.\n";
2277                 return NULL;
2278
2279         } else if (cmd == CLI_GENERATE) {
2280                 /* skip first 14 or 15 chars, "core show help " */
2281                 int l = strlen(a->line);
2282
2283                 if (l > 15) {
2284                         l = 15;
2285                 }
2286                 /* XXX watch out, should stop to the non-generator parts */
2287                 return __ast_cli_generator(a->line + l, a->word, a->n, 0);
2288         }
2289         if (a->argc == e->args) {
2290                 return help1(a->fd, NULL, 0);
2291         }
2292
2293         AST_RWLIST_RDLOCK(&helpers);
2294         my_e = find_cli(a->argv + 3, 1);        /* try exact match first */
2295         if (!my_e) {
2296                 res = help1(a->fd, a->argv + 3, 1 /* locked */);
2297                 AST_RWLIST_UNLOCK(&helpers);
2298                 return res;
2299         }
2300         if (my_e->usage)
2301                 ast_cli(a->fd, "%s", my_e->usage);
2302         else {
2303                 ast_join(fullcmd, sizeof(fullcmd), a->argv + 3);
2304                 ast_cli(a->fd, "No help text available for '%s'.\n", fullcmd);
2305         }
2306         AST_RWLIST_UNLOCK(&helpers);
2307         return res;
2308 }
2309
2310 static char *parse_args(const char *s, int *argc, const char *argv[], int max, int *trailingwhitespace)
2311 {
2312         char *duplicate, *cur;
2313         int x = 0;
2314         int quoted = 0;
2315         int escaped = 0;
2316         int whitespace = 1;
2317         int dummy = 0;
2318
2319         if (trailingwhitespace == NULL)
2320                 trailingwhitespace = &dummy;
2321         *trailingwhitespace = 0;
2322         if (s == NULL)  /* invalid, though! */
2323                 return NULL;
2324         /* make a copy to store the parsed string */
2325         if (!(duplicate = ast_strdup(s)))
2326                 return NULL;
2327
2328         cur = duplicate;
2329         /* scan the original string copying into cur when needed */
2330         for (; *s ; s++) {
2331                 if (x >= max - 1) {
2332                         ast_log(LOG_WARNING, "Too many arguments, truncating at %s\n", s);
2333                         break;
2334                 }
2335                 if (*s == '"' && !escaped) {
2336                         quoted = !quoted;
2337                         if (quoted && whitespace) {
2338                                 /* start a quoted string from previous whitespace: new argument */
2339                                 argv[x++] = cur;
2340                                 whitespace = 0;
2341                         }
2342                 } else if ((*s == ' ' || *s == '\t') && !(quoted || escaped)) {
2343                         /* If we are not already in whitespace, and not in a quoted string or
2344                            processing an escape sequence, and just entered whitespace, then
2345                            finalize the previous argument and remember that we are in whitespace
2346                         */
2347                         if (!whitespace) {
2348                                 *cur++ = '\0';
2349                                 whitespace = 1;
2350                         }
2351                 } else if (*s == '\\' && !escaped) {
2352                         escaped = 1;
2353                 } else {
2354                         if (whitespace) {
2355                                 /* we leave whitespace, and are not quoted. So it's a new argument */
2356                                 argv[x++] = cur;
2357                                 whitespace = 0;
2358                         }
2359                         *cur++ = *s;
2360                         escaped = 0;
2361                 }
2362         }
2363         /* Null terminate */
2364         *cur++ = '\0';
2365         /* XXX put a NULL in the last argument, because some functions that take
2366          * the array may want a null-terminated array.
2367          * argc still reflects the number of non-NULL entries.
2368          */
2369         argv[x] = NULL;
2370         *argc = x;
2371         *trailingwhitespace = whitespace;
2372         return duplicate;
2373 }
2374
2375 /*! \brief Return the number of unique matches for the generator */
2376 int ast_cli_generatornummatches(const char *text, const char *word)
2377 {
2378         int matches = 0, i = 0;
2379         char *buf = NULL, *oldbuf = NULL;
2380
2381         while ((buf = ast_cli_generator(text, word, i++))) {
2382                 if (!oldbuf || strcmp(buf,oldbuf))
2383                         matches++;
2384                 if (oldbuf)
2385                         ast_free(oldbuf);
2386                 oldbuf = buf;
2387         }
2388         if (oldbuf)
2389                 ast_free(oldbuf);
2390         return matches;
2391 }
2392
2393 char **ast_cli_completion_matches(const char *text, const char *word)
2394 {
2395         char **match_list = NULL, *retstr, *prevstr;
2396         size_t match_list_len, max_equal, which, i;
2397         int matches = 0;
2398
2399         /* leave entry 0 free for the longest common substring */
2400         match_list_len = 1;
2401         while ((retstr = ast_cli_generator(text, word, matches)) != NULL) {
2402                 if (matches + 1 >= match_list_len) {
2403                         match_list_len <<= 1;
2404                         if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(*match_list))))
2405                                 return NULL;
2406                 }
2407                 match_list[++matches] = retstr;
2408         }
2409
2410         if (!match_list)
2411                 return match_list; /* NULL */
2412
2413         /* Find the longest substring that is common to all results
2414          * (it is a candidate for completion), and store a copy in entry 0.
2415          */
2416         prevstr = match_list[1];
2417         max_equal = strlen(prevstr);
2418         for (which = 2; which <= matches; which++) {
2419                 for (i = 0; i < max_equal && toupper(prevstr[i]) == toupper(match_list[which][i]); i++)
2420                         continue;
2421                 max_equal = i;
2422         }
2423
2424         if (!(retstr = ast_malloc(max_equal + 1))) {
2425                 ast_free(match_list);
2426                 return NULL;
2427         }
2428
2429         ast_copy_string(retstr, match_list[1], max_equal + 1);
2430         match_list[0] = retstr;
2431
2432         /* ensure that the array is NULL terminated */
2433         if (matches + 1 >= match_list_len) {
2434                 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(*match_list)))) {
2435                         ast_free(retstr);
2436                         return NULL;
2437                 }
2438         }
2439         match_list[matches + 1] = NULL;
2440
2441         return match_list;
2442 }
2443
2444 /*! \brief returns true if there are more words to match */
2445 static int more_words (const char * const *dst)
2446 {
2447         int i;
2448         for (i = 0; dst[i]; i++) {
2449                 if (dst[i][0] != '[')
2450                         return -1;
2451         }
2452         return 0;
2453 }
2454
2455 /*
2456  * generate the entry at position 'state'
2457  */
2458 static char *__ast_cli_generator(const char *text, const char *word, int state, int lock)
2459 {
2460         const char *argv[AST_MAX_ARGS];
2461         struct ast_cli_entry *e = NULL;
2462         int x = 0, argindex, matchlen;
2463         int matchnum=0;
2464         char *ret = NULL;
2465         char matchstr[80] = "";
2466         int tws = 0;
2467         /* Split the argument into an array of words */
2468         char *duplicate = parse_args(text, &x, argv, ARRAY_LEN(argv), &tws);
2469
2470         if (!duplicate) /* malloc error */
2471                 return NULL;
2472
2473         /* Compute the index of the last argument (could be an empty string) */
2474         argindex = (!ast_strlen_zero(word) && x>0) ? x-1 : x;
2475
2476         /* rebuild the command, ignore terminating white space and flatten space */
2477         ast_join(matchstr, sizeof(matchstr)-1, argv);
2478         matchlen = strlen(matchstr);
2479         if (tws) {
2480                 strcat(matchstr, " "); /* XXX */
2481                 if (matchlen)
2482                         matchlen++;
2483         }
2484         if (lock)
2485                 AST_RWLIST_RDLOCK(&helpers);
2486         while ( (e = cli_next(e)) ) {
2487                 /* XXX repeated code */
2488                 int src = 0, dst = 0, n = 0;
2489
2490                 if (e->command[0] == '_')
2491                         continue;
2492
2493                 /*
2494                  * Try to match words, up to and excluding the last word, which
2495                  * is either a blank or something that we want to extend.
2496                  */
2497                 for (;src < argindex; dst++, src += n) {
2498                         n = word_match(argv[src], e->cmda[dst]);
2499                         if (n < 0)
2500                                 break;
2501                 }
2502
2503                 if (src != argindex && more_words(e->cmda + dst))       /* not a match */
2504                         continue;
2505                 ret = is_prefix(argv[src], e->cmda[dst], state - matchnum, &n);
2506                 matchnum += n;  /* this many matches here */
2507                 if (ret) {
2508                         /*
2509                          * argv[src] is a valid prefix of the next word in this
2510                          * command. If this is also the correct entry, return it.
2511                          */
2512                         if (matchnum > state)
2513                                 break;
2514                         ast_free(ret);
2515                         ret = NULL;
2516                 } else if (ast_strlen_zero(e->cmda[dst])) {
2517                         /*
2518                          * This entry is a prefix of the command string entered
2519                          * (only one entry in the list should have this property).
2520                          * Run the generator if one is available. In any case we are done.
2521                          */
2522                         if (e->handler) {       /* new style command */
2523                                 struct ast_cli_args a = {
2524                                         .line = matchstr, .word = word,
2525                                         .pos = argindex,
2526                                         .n = state - matchnum,
2527                                         .argv = argv,
2528                                         .argc = x};
2529                                 ret = e->handler(e, CLI_GENERATE, &a);
2530                         }
2531                         if (ret)
2532                                 break;
2533                 }
2534         }
2535         if (lock)
2536                 AST_RWLIST_UNLOCK(&helpers);
2537         ast_free(duplicate);
2538         return ret;
2539 }
2540
2541 char *ast_cli_generator(const char *text, const char *word, int state)
2542 {
2543         return __ast_cli_generator(text, word, state, 1);
2544 }
2545
2546 int ast_cli_command_full(int uid, int gid, int fd, const char *s)
2547 {
2548         const char *args[AST_MAX_ARGS + 1];
2549         struct ast_cli_entry *e;
2550         int x;
2551         char *duplicate = parse_args(s, &x, args + 1, AST_MAX_ARGS, NULL);
2552         char tmp[AST_MAX_ARGS + 1];
2553         char *retval = NULL;
2554         struct ast_cli_args a = {
2555                 .fd = fd, .argc = x, .argv = args+1 };
2556
2557         if (duplicate == NULL)
2558                 return -1;
2559
2560         if (x < 1)      /* We need at least one entry, otherwise ignore */
2561                 goto done;
2562
2563         AST_RWLIST_RDLOCK(&helpers);
2564         e = find_cli(args + 1, 0);
2565         if (e)
2566                 ast_atomic_fetchadd_int(&e->inuse, 1);
2567         AST_RWLIST_UNLOCK(&helpers);
2568         if (e == NULL) {
2569                 ast_cli(fd, "No such command '%s' (type 'core show help %s' for other possible commands)\n", s, find_best(args + 1));
2570                 goto done;
2571         }
2572
2573         ast_join(tmp, sizeof(tmp), args + 1);
2574         /* Check if the user has rights to run this command. */
2575         if (!cli_has_permissions(uid, gid, tmp)) {
2576                 ast_cli(fd, "You don't have permissions to run '%s' command\n", tmp);
2577                 ast_free(duplicate);
2578                 return 0;
2579         }
2580
2581         /*
2582          * Within the handler, argv[-1] contains a pointer to the ast_cli_entry.
2583          * Remember that the array returned by parse_args is NULL-terminated.
2584          */
2585         args[0] = (char *)e;
2586
2587         retval = e->handler(e, CLI_HANDLER, &a);
2588
2589         if (retval == CLI_SHOWUSAGE) {
2590                 ast_cli(fd, "%s", S_OR(e->usage, "Invalid usage, but no usage information available.\n"));
2591         } else {
2592                 if (retval == CLI_FAILURE)
2593                         ast_cli(fd, "Command '%s' failed.\n", s);
2594         }
2595         ast_atomic_fetchadd_int(&e->inuse, -1);
2596 done:
2597         ast_free(duplicate);
2598         return 0;
2599 }
2600
2601 int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const char *s)
2602 {
2603         char cmd[512];
2604         int x, y = 0, count = 0;
2605
2606         for (x = 0; x < size; x++) {
2607                 cmd[y] = s[x];
2608                 y++;
2609                 if (s[x] == '\0') {
2610                         ast_cli_command_full(uid, gid, fd, cmd);
2611                         y = 0;
2612                         count++;
2613                 }
2614         }
2615         return count;
2616 }