Address JSON thread safety issues.
[asterisk/asterisk.git] / res / ari / cli.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@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 Command line for ARI.
22  * \author David M. Lee, II <dlee@digium.com>
23  */
24
25 #include "asterisk.h"
26
27 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
28
29 #include "asterisk/astobj2.h"
30 #include "asterisk/cli.h"
31 #include "internal.h"
32
33 static char *ari_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
34 {
35         RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
36
37         switch (cmd) {
38         case CLI_INIT:
39                 e->command = "ari show status";
40                 e->usage =
41                         "Usage: ari show status\n"
42                         "       Shows all ARI settings\n";
43                 return NULL;
44         case CLI_GENERATE:
45                 return NULL;
46         default:
47                 break;
48         }
49
50         if (a->argc != 3) {
51                 return CLI_SHOWUSAGE;
52         }
53
54         conf = ast_ari_config_get();
55
56         if (!conf) {
57                 ast_cli(a->fd, "Error getting ARI configuration\n");
58                 return CLI_FAILURE;
59         }
60
61         ast_cli(a->fd, "ARI Status:\n");
62         ast_cli(a->fd, "Enabled: %s\n", AST_CLI_YESNO(conf->general->enabled));
63         ast_cli(a->fd, "Output format: ");
64         switch (conf->general->format) {
65         case AST_JSON_COMPACT:
66                 ast_cli(a->fd, "compact");
67                 break;
68         case AST_JSON_PRETTY:
69                 ast_cli(a->fd, "pretty");
70                 break;
71         }
72         ast_cli(a->fd, "\n");
73         ast_cli(a->fd, "Auth realm: %s\n", conf->general->auth_realm);
74         ast_cli(a->fd, "Allowed Origins: %s\n", conf->general->allowed_origins);
75         ast_cli(a->fd, "User count: %d\n", ao2_container_count(conf->users));
76         return CLI_SUCCESS;
77 }
78
79 static int show_users_cb(void *obj, void *arg, int flags)
80 {
81         struct ast_ari_conf_user *user = obj;
82         struct ast_cli_args *a = arg;
83
84         ast_cli(a->fd, "%-4s  %s\n",
85                 AST_CLI_YESNO(user->read_only),
86                 user->username);
87         return 0;
88 }
89
90 static char *ari_show_users(struct ast_cli_entry *e, int cmd,
91         struct ast_cli_args *a)
92 {
93         RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
94
95         switch (cmd) {
96         case CLI_INIT:
97                 e->command = "ari show users";
98                 e->usage =
99                         "Usage: ari show users\n"
100                         "       Shows all ARI users\n";
101                 return NULL;
102         case CLI_GENERATE:
103                 return NULL;
104         default:
105                 break;
106         }
107
108         if (a->argc != 3) {
109                 return CLI_SHOWUSAGE;
110         }
111
112         conf = ast_ari_config_get();
113         if (!conf) {
114                 ast_cli(a->fd, "Error getting ARI configuration\n");
115                 return CLI_FAILURE;
116         }
117
118         ast_cli(a->fd, "r/o?  Username\n");
119         ast_cli(a->fd, "----  --------\n");
120
121         ao2_callback(conf->users, OBJ_NODATA, show_users_cb, a);
122
123         return CLI_SUCCESS;
124 }
125
126 struct user_complete {
127         /*! Nth user to search for */
128         int state;
129         /*! Which user currently on */
130         int which;
131 };
132
133 static int complete_ari_user_search(void *obj, void *arg, void *data, int flags)
134 {
135         struct user_complete *search = data;
136
137         if (++search->which > search->state) {
138                 return CMP_MATCH;
139         }
140         return 0;
141 }
142
143 static char *complete_ari_user(struct ast_cli_args *a)
144 {
145         RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
146         RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
147
148         struct user_complete search = {
149                 .state = a->n,
150         };
151
152         conf = ast_ari_config_get();
153         if (!conf) {
154                 ast_cli(a->fd, "Error getting ARI configuration\n");
155                 return CLI_FAILURE;
156         }
157
158         user = ao2_callback_data(conf->users,
159                 ast_strlen_zero(a->word) ? 0 : OBJ_PARTIAL_KEY,
160                 complete_ari_user_search, (char*)a->word, &search);
161
162         return user ? ast_strdup(user->username) : NULL;
163 }
164
165 static char *complete_ari_show_user(struct ast_cli_args *a)
166 {
167         if (a->pos == 3) {
168                 return complete_ari_user(a);
169         }
170
171         return NULL;
172 }
173
174 static char *ari_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
175 {
176         RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
177         RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
178
179         switch (cmd) {
180         case CLI_INIT:
181                 e->command = "ari show user";
182                 e->usage =
183                         "Usage: ari show user <username>\n"
184                         "       Shows a specific ARI user\n";
185                 return NULL;
186         case CLI_GENERATE:
187                 return complete_ari_show_user(a);
188         default:
189                 break;
190         }
191
192         if (a->argc != 4) {
193                 return CLI_SHOWUSAGE;
194         }
195
196         conf = ast_ari_config_get();
197
198         if (!conf) {
199                 ast_cli(a->fd, "Error getting ARI configuration\n");
200                 return CLI_FAILURE;
201         }
202
203         user = ao2_find(conf->users, a->argv[3], OBJ_KEY);
204         if (!user) {
205                 ast_cli(a->fd, "User '%s' not found\n", a->argv[3]);
206                 return CLI_SUCCESS;
207         }
208
209         ast_cli(a->fd, "Username: %s\n", user->username);
210         ast_cli(a->fd, "Read only?: %s\n", AST_CLI_YESNO(user->read_only));
211
212         return CLI_SUCCESS;
213 }
214
215 static char *ari_mkpasswd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
216 {
217         RAII_VAR(char *, crypted, NULL, ast_free);
218
219         switch (cmd) {
220         case CLI_INIT:
221                 e->command = "ari mkpasswd";
222                 e->usage =
223                         "Usage: ari mkpasswd <password>\n"
224                         "       Encrypts a password for use in ari.conf\n"
225                         "       Be aware that the password will be shown in the\n"
226                         "       command line history. The mkpasswd shell command\n"
227                         "       may be preferable.\n"
228                         ;
229                 return NULL;
230         case CLI_GENERATE:
231                 return NULL;
232         default:
233                 break;
234         }
235
236         if (a->argc != 3) {
237                 return CLI_SHOWUSAGE;
238         }
239
240         crypted = ast_crypt_encrypt(a->argv[2]);
241         if (!crypted) {
242                 ast_cli(a->fd, "Failed to encrypt password\n");
243                 return CLI_FAILURE;
244         }
245
246         ast_cli(a->fd,
247                 "; Copy the following two lines into ari.conf\n");
248         ast_cli(a->fd, "password_format = crypt\n");
249         ast_cli(a->fd, "password = %s\n", crypted);
250
251         return CLI_SUCCESS;
252 }
253
254 static struct ast_cli_entry cli_ari[] = {
255         AST_CLI_DEFINE(ari_show, "Show ARI settings"),
256         AST_CLI_DEFINE(ari_show_users, "List ARI users"),
257         AST_CLI_DEFINE(ari_show_user, "List single ARI user"),
258         AST_CLI_DEFINE(ari_mkpasswd, "Encrypts a password"),
259 };
260
261 int ast_ari_cli_register(void) {
262         return ast_cli_register_multiple(cli_ari, ARRAY_LEN(cli_ari));
263 }
264
265 void ast_ari_cli_unregister(void) {
266         ast_cli_unregister_multiple(cli_ari, ARRAY_LEN(cli_ari));
267 }