Add depend on pjproject to res_pjsip_config_wizard.c
[asterisk/asterisk.git] / res / res_pjsip_config_wizard.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2014, Fairview 5 Engineering, LLC
5  *
6  * George Joseph <george.joseph@fairview5.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 PJSIP Configuration Wizard
22  *
23  * \author George Joseph <george.joseph@fairview5.com>
24   */
25
26 /*! \li \ref res_pjsip_config_wizard.c uses the configuration file \ref pjsip_wizard.conf
27  */
28
29 /*!
30  * \page pjsip_wizard.conf pjsip_wizard.conf
31  * \verbinclude pjsip_wizard.conf.sample
32  */
33
34 /*** MODULEINFO
35         <depend>pjproject</depend>
36         <depend>res_pjsip</depend>
37         <support_level>core</support_level>
38  ***/
39
40 #include "asterisk.h"
41
42 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43
44 #include <regex.h>
45 #include <pjsip.h>
46
47 #include "asterisk/astobj2.h"
48 #include "asterisk/res_pjsip.h"
49 #include "asterisk/module.h"
50 #include "asterisk/pbx.h"
51 #include "asterisk/sorcery.h"
52 #include "asterisk/vector.h"
53
54 /*** DOCUMENTATION
55         <configInfo name="res_pjsip_config_wizard" language="en_US">
56                 <synopsis>Module that privides simple configuration wizard capabilities.</synopsis>
57                 <description><para>
58                         <emphasis>PJSIP Configuration Wizard</emphasis>
59                         </para>
60                         <para>This module allows creation of common PJSIP configuration scenarios
61                         without having to specify individual endpoint, aor, auth, identify and registration objects.
62                         </para>
63                         <para> </para>
64
65                         <para>For example, the following configuration snippet would create the
66                         endpoint, aor, contact, auth and phoneprov objects necessary for a phone to
67                         get phone provisioning information, register, and make and receive calls.</para>
68                         <para> </para>
69
70                         <para>[myphone]</para>
71                         <para>type = wizard</para>
72                         <para>sends_auth = no</para>
73                         <para>accepts_auth = yes</para>
74                         <para>sends_registrations = no</para>
75                         <para>accepts_registrations = yes</para>
76                         <para>has_phoneprov = yes</para>
77                         <para>transport = ipv4</para>
78                         <para>inbound_auth/username = testname</para>
79                         <para>inbound_auth/password = test password</para>
80                         <para>endpoint/allow = ulaw</para>
81                         <para>endpoint/context = default</para>
82                         <para>phoneprov/MAC = 001122aa4455</para>
83                         <para>phoneprov/PROFILE = profile1</para>
84                         <para> </para>
85
86                         <para>The first 7 items are specific to the wizard.  The rest of the items
87                         are passed verbatim to the underlying objects.</para>
88                         <para> </para>
89
90                         <para>The following configuration snippet would create the
91                         endpoint, aor, contact, auth, identify and registration objects necessary for a trunk
92                         to another pbx or ITSP that requires registration.</para>
93                         <para> </para>
94
95                         <para>[mytrunk]</para>
96                         <para>type = wizard</para>
97                         <para>sends_auth = yes</para>
98                         <para>accepts_auth = no</para>
99                         <para>sends_registrations = yes</para>
100                         <para>accepts_registrations = no</para>
101                         <para>transport = ipv4</para>
102                         <para>remote_hosts = sip1.myitsp.com:5060,sip2.myitsp.com:5060</para>
103                         <para>outbound_auth/username = testname</para>
104                         <para>outbound_auth/password = test password</para>
105                         <para>endpoint/allow = ulaw</para>
106                         <para>endpoint/context = default</para>
107                         <para> </para>
108
109                         <para>Of course, any of the items in either example could be placed into
110                         templates and shared among wizard objects.</para>
111                 </description>
112
113                 <configFile name="pjsip_wizard.conf">
114                         <configObject name="wizard">
115                                 <synopsis>Provides config wizard.</synopsis>
116                                 <configOption name="type">
117                                         <synopsis>Must be 'wizard'.</synopsis>
118                                 </configOption>
119                                 <configOption name="transport">
120                                         <synopsis>The name of a transport to use for this object.</synopsis>
121                                         <description><para>If not specified,
122                                         the default will be used.</para></description>
123                                 </configOption>
124                                 <configOption name="remote_hosts">
125                                         <synopsis>List of remote hosts.</synopsis>
126                                         <description><para>A comma-separated list of remote hosts in the form of
127                                         <replaceable>host</replaceable>[:<replaceable>port</replaceable>].
128                                         If set, an aor static contact and an identify match will be created for each
129                                         entry in the list.  If send_registrations is also set, a registration will
130                                         also be created for each.</para></description>
131                                 </configOption>
132                                 <configOption name="sends_auth" default="no">
133                                         <synopsis>Send outbound authentication to remote hosts.</synopsis>
134                                         <description><para>At least outbound_auth/username is required.</para></description>
135                                 </configOption>
136                                 <configOption name="accepts_auth" default="no">
137                                         <synopsis>Accept incoming authentication from remote hosts.</synopsis>
138                                         <description><para>At least inbound_auth/username is required.</para></description>
139                                 </configOption>
140                                 <configOption name="sends_registrations" default="no">
141                                         <synopsis>Send outbound registrations to remote hosts.</synopsis>
142                                         <description><para>remote_hosts is required and a registration object will
143                                         be created for each host in the remote _hosts string.  If authentication is required,
144                                         sends_auth and an outbound_auth/username must also be supplied.</para></description>
145                                 </configOption>
146                                 <configOption name="accepts_registrations" default="no">
147                                         <synopsis>Accept inbound registration from remote hosts.</synopsis>
148                                         <description><para>An AOR with dynamic contacts will be created.  If
149                                         the number of contacts nneds to be limited, set aor/max_contacts.</para></description>
150                                 </configOption>
151                                 <configOption name="has_phoneprov" default="no">
152                                         <synopsis>Create a phoneprov object for this endpoint.</synopsis>
153                                         <description><para>A phoneprov object will be created.  phoneprov/MAC
154                                         must be specified.</para></description>
155                                 </configOption>
156                                 <configOption name="server_uri_pattern" default="sip:${REMOTE_HOST}">
157                                         <synopsis>A pattern to use for constructing outbound registration server_uris.</synopsis>
158                                         <description><para>
159                                         The literal <literal>${REMOTE_HOST}</literal> will be substituted with the
160                                         appropriate remote_host for each registration.</para></description>
161                                 </configOption>
162                                 <configOption name="client_uri_pattern" default="sip:${USERNAME}@${REMOTE_HOST}">
163                                         <synopsis>A pattern to use for constructing outbound registration client_uris.</synopsis>
164                                         <description><para>
165                                         The literals <literal>${REMOTE_HOST}</literal> and <literal>${USERNAME}</literal>
166                                         will be substituted with the appropriate remote_host and outbound_auth/username.</para></description>
167                                 </configOption>
168                                 <configOption name="contact_pattern" default="sip:${REMOTE_HOST}">
169                                         <synopsis>A pattern to use for constructing outbound contact uris.</synopsis>
170                                         <description><para>
171                                         The literal <literal>${REMOTE_HOST}</literal> will be substituted with the
172                                         appropriate remote_host for each contact.</para></description>
173                                 </configOption>
174                                 <configOption name="endpoint&#47;*">
175                                         <synopsis>Variables to be passed directly to the endpoint.</synopsis>
176                                 </configOption>
177                                 <configOption name="aor&#47;*">
178                                         <synopsis>Variables to be passed directly to the aor.</synopsis>
179                                         <description><para>If an aor/contact is explicitly defined then remote_hosts
180                                         will not be used to create contacts automatically.</para></description>
181                                 </configOption>
182                                 <configOption name="inbound_auth&#47;*">
183                                         <synopsis>Variables to be passed directly to the inbound auth.</synopsis>
184                                 </configOption>
185                                 <configOption name="outbound_auth&#47;*">
186                                         <synopsis>Variables to be passed directly to the outbound auth.</synopsis>
187                                 </configOption>
188                                 <configOption name="identify&#47;*">
189                                         <synopsis>Variables to be passed directly to the identify.</synopsis>
190                                         <description><para>If an identify/match is explicitly defined then remote_hosts
191                                         will not be used to create matches automatically.</para></description>
192                                 </configOption>
193                                 <configOption name="registration&#47;*">
194                                         <synopsis>Variables to be passed directly to the outbound registrations.</synopsis>
195                                 </configOption>
196                                 <configOption name="phoneprov&#47;*">
197                                         <synopsis>Variables to be passed directly to the phoneprov object.</synopsis>
198                                         <description><para>
199                                         To activate phoneprov, at least phoneprov/MAC must be set.</para></description>
200                                 </configOption>
201                         </configObject>
202                 </configFile>
203         </configInfo>
204  ***/
205
206  /*! \brief Defines the maximum number of characters that can be added to a wizard id. */
207 #define MAX_ID_SUFFIX 20
208
209 /*! \brief A generic char * vector definition. */
210 AST_VECTOR(string_vector, char *);
211
212 /*! \brief Keeps track of the sorcery wizard and last config for each object type */
213 struct object_type_wizard {
214         struct ast_sorcery *sorcery;
215         struct ast_sorcery_wizard *wizard;
216         void *wizard_data;
217         struct ast_config *last_config;
218         char object_type[];
219 };
220 static AST_VECTOR(object_type_wizards, struct object_type_wizard *) object_type_wizards;
221
222 /*! \brief Callbacks for vector deletes */
223 #define NOT_EQUALS(a, b) (a != b)
224 #define OTW_DELETE_CB(otw) ({ \
225         ast_config_destroy(otw->last_config); \
226         ast_free(otw); \
227 })
228
229 const static char *object_types[] = {"phoneprov", "registration", "identify", "endpoint", "aor", "auth", NULL};
230
231 static int is_one_of(const char *needle, const char *haystack[])
232 {
233         int i;
234         for (i = 0; haystack[i]; i++) {
235                 if (!strcmp(needle, haystack[i])) {
236                         return 1;
237                 }
238         }
239
240         return 0;
241 }
242
243 /*! \brief Finds the otw for the object type */
244 static struct object_type_wizard *find_wizard(const char *object_type)
245 {
246         int idx;
247
248         for(idx = 0; idx < AST_VECTOR_SIZE(&object_type_wizards); idx++) {
249                 struct object_type_wizard *otw = AST_VECTOR_GET(&object_type_wizards, idx);
250                 if (!strcmp(otw->object_type, object_type)) {
251                         return otw;
252                 }
253         }
254
255         return NULL;
256 }
257
258 /*! \brief Creates a sorcery object and applies a variable list */
259 static void *create_object(const struct ast_sorcery *sorcery,
260         const char *id, const char *type, struct ast_variable *vars)
261 {
262         struct ast_sorcery_object *obj = ast_sorcery_alloc(sorcery, type, id);
263
264         if (!obj) {
265                 ast_log(LOG_ERROR, "Unable to allocate an object of type '%s' with id '%s'.\n", type, id);
266                 return NULL;
267         }
268
269         if (ast_sorcery_objectset_apply(sorcery, obj, vars)) {
270                 ast_log(LOG_ERROR, "Unable to apply object type '%s' with id '%s'.  Check preceeding errors.\n", type, id);
271                 ao2_ref(obj, -1);
272                 return NULL;
273         }
274
275         return obj;
276 }
277
278 /*! \brief Finds a variable in a list and tests it */
279 static int is_variable_true(struct ast_variable *vars, const char *name)
280 {
281         return ast_true(ast_variable_find_in_list(vars, name));
282 }
283
284 /*! \brief Appends a variable to the end of an existing list */
285 static int variable_list_append(struct ast_variable **existing, const char *name, const char *value)
286 {
287         struct ast_variable *new = ast_variable_new(name, value, "");
288
289         if (!new) {
290                 ast_log(LOG_ERROR, "Unable to allocate memory for new variable '%s'.\n", name);
291                 return -1;
292         }
293
294         ast_variable_list_append(existing, new);
295
296         return 0;
297 }
298
299 /*! \brief Appends a variable to the end of an existing list.  On failure, cause the calling
300  * function to return -1 */
301 #define variable_list_append_return(existing, name, value) ({ \
302         struct ast_variable *new = ast_variable_new(name, value, ""); \
303         if (!new) { \
304                 ast_log(LOG_ERROR, "Unable to allocate memory for new variable '%s'.\n", name); \
305                 return -1; \
306         } \
307         ast_variable_list_append(existing, new); \
308 })
309
310 /*! \brief We need to strip off the prefix from the name of each variable
311  * so they're suitable for objectset_apply.
312  * I.E.  will transform outbound_auth/username to username.
313  */
314 static struct ast_variable *get_object_variables(struct ast_variable *vars, char *prefix)
315 {
316         struct ast_variable *return_vars = NULL;
317         struct ast_variable *v = vars;
318         int plen = strlen(prefix);
319
320         for(; v; v = v->next) {
321                 if (ast_begins_with(v->name, prefix) && strlen(v->name) > plen) {
322                         if (variable_list_append(&return_vars, v->name + plen, v->value)) {
323                                 ast_variables_destroy(return_vars);
324                                 return NULL;
325                         }
326                 }
327         }
328
329         return return_vars;
330 }
331
332 static int handle_auth(const struct ast_sorcery *sorcery, struct object_type_wizard *otw,
333         struct ast_category *wiz, char *direction)
334 {
335         struct ast_variable *wizvars = ast_category_first(wiz);
336         struct ast_sorcery_object *obj = NULL;
337         const char *id = ast_category_get_name(wiz);
338         char new_id[strlen(id) + MAX_ID_SUFFIX];
339         char prefix[strlen(direction) + strlen("_auth/") + 1];
340         char *test_variable = NULL;
341         RAII_VAR(struct ast_variable *, vars, NULL, ast_variables_destroy);
342
343         snprintf(prefix, sizeof(prefix), "%s_auth/", direction);
344         vars = get_object_variables(wizvars, prefix);
345
346         if (!strcmp(direction, "outbound")) {
347                 snprintf(new_id, sizeof(new_id), "%s-oauth", id);
348                 test_variable = "sends_auth";
349         } else {
350                 snprintf(new_id, sizeof(new_id), "%s-iauth", id);
351                 test_variable = "accepts_auth";
352         }
353
354         if (is_variable_true(wizvars, test_variable)) {
355                 if (!ast_variable_find_in_list(vars, "username")) {
356                         ast_log(LOG_ERROR,
357                                 "Wizard '%s' must have '%s_auth/username' if it %s.\n", id, direction, test_variable);
358                         return -1;
359                 }
360         } else {
361                 /* Delete auth if sends or accepts is now false. */
362                 obj = otw->wizard->retrieve_id(sorcery, otw->wizard_data, "auth", new_id);
363                 if (obj) {
364                         otw->wizard->delete(sorcery, otw->wizard_data, obj);
365                         ao2_ref(obj, -1);
366                 }
367                 return 0;
368         }
369
370         variable_list_append_return(&vars, "@pjsip_wizard", id);
371
372         /* If the user set auth_type, don't override it. */
373         if (!ast_variable_find_in_list(vars, "auth_type")) {
374                 variable_list_append_return(&vars, "auth_type", "userpass");
375         }
376
377         obj = create_object(sorcery, new_id, "auth", vars);
378         if (!obj) {
379                 return -1;
380         }
381
382         if (otw->wizard->update(sorcery, otw->wizard_data, obj)) {
383                 otw->wizard->create(sorcery, otw->wizard_data, obj);
384         }
385         ao2_ref(obj, -1);
386
387         return 0;
388 }
389
390 static int handle_auths(const struct ast_sorcery *sorcery, struct object_type_wizard *otw,
391         struct ast_category *wiz)
392 {
393         int rc;
394
395         if ((rc = handle_auth(sorcery, otw, wiz, "outbound"))) {
396                 return rc;
397         }
398
399         return handle_auth(sorcery, otw, wiz, "inbound");
400 }
401
402 static int handle_aor(const struct ast_sorcery *sorcery, struct object_type_wizard *otw,
403         struct ast_category *wiz, struct string_vector *remote_hosts_vector)
404 {
405         struct ast_variable *wizvars = ast_category_first(wiz);
406         struct ast_sorcery_object *obj = NULL;
407         const char *id = ast_category_get_name(wiz);
408         const char *contact_pattern;
409         int host_count = AST_VECTOR_SIZE(remote_hosts_vector);
410         RAII_VAR(struct ast_variable *, vars, get_object_variables(wizvars, "aor/"), ast_variables_destroy);
411
412         variable_list_append(&vars, "@pjsip_wizard", id);
413
414         /* If the user explicitly specified an aor/contact, don't use remote hosts. */
415         if (!ast_variable_find_in_list(vars, "contact")) {
416                 if (!(contact_pattern = ast_variable_find_in_list(wizvars, "contact_pattern"))) {
417                         contact_pattern = "sip:${REMOTE_HOST}";
418                 }
419
420                 if (host_count > 0 && !ast_strlen_zero(contact_pattern)) {
421                         int host_counter;
422
423                         /* ast_str_substitute_variables operate on a varshead list so we have
424                          * to create one to hold the REPORT_HOST substitution, do the substitution,
425                          * then append the result to the ast_variable list.
426                          */
427                         for (host_counter = 0; host_counter < host_count; host_counter++) {
428                                 RAII_VAR(struct ast_str *, new_str, ast_str_create(64), ast_free);
429                                 RAII_VAR(struct varshead *, subst_vars, ast_var_list_create(), ast_var_list_destroy);
430                                 struct ast_var_t *var = ast_var_assign("REMOTE_HOST",
431                                         AST_VECTOR_GET(remote_hosts_vector, host_counter));
432
433                                 AST_VAR_LIST_INSERT_TAIL(subst_vars, var);
434                                 ast_str_substitute_variables_varshead(&new_str, 0, subst_vars,
435                                         contact_pattern);
436
437                                 variable_list_append_return(&vars, "contact", ast_str_buffer(new_str));
438                         }
439                 }
440         }
441
442         obj = create_object(sorcery, id, "aor", vars);
443         if (!obj) {
444                 return -1;
445         }
446
447         if (otw->wizard->update(sorcery, otw->wizard_data, obj)) {
448                 otw->wizard->create(sorcery, otw->wizard_data, obj);
449         }
450         ao2_ref(obj, -1);
451
452         return 0;
453 }
454
455 static int handle_endpoint(const struct ast_sorcery *sorcery, struct object_type_wizard *otw,
456         struct ast_category *wiz)
457 {
458         struct ast_variable *wizvars = ast_category_first(wiz);
459         struct ast_sorcery_object *obj = NULL;
460         const char *id = ast_category_get_name(wiz);
461         const char *transport = ast_variable_find_in_list(wizvars, "transport");
462         char new_id[strlen(id) + MAX_ID_SUFFIX];
463         RAII_VAR(struct ast_variable *, vars, get_object_variables(wizvars, "endpoint/"), ast_variables_destroy);
464
465         variable_list_append_return(&vars, "@pjsip_wizard", id);
466         variable_list_append_return(&vars, "aors", id);
467
468         if (!ast_strlen_zero(transport)) {
469                 variable_list_append_return(&vars, "transport", transport);
470         }
471
472         if (is_variable_true(wizvars, "sends_auth")) {
473                 snprintf(new_id, sizeof(new_id), "%s-oauth", id);
474                 variable_list_append_return(&vars, "outbound_auth", new_id);
475         }
476
477         if (is_variable_true(wizvars, "accepts_auth")) {
478                 snprintf(new_id, sizeof(new_id), "%s-iauth", id);
479                 variable_list_append_return(&vars, "auth", new_id);
480         }
481
482         obj = create_object(sorcery, id, "endpoint", vars);
483         if (!obj) {
484                 return -1;
485         }
486
487         if (otw->wizard->update(sorcery, otw->wizard_data, obj)) {
488                 otw->wizard->create(sorcery, otw->wizard_data, obj);
489         }
490         ao2_ref(obj, -1);
491
492         return 0;
493 }
494
495 static int handle_identify(const struct ast_sorcery *sorcery, struct object_type_wizard *otw,
496         struct ast_category *wiz, struct string_vector *remote_hosts_vector)
497 {
498         struct ast_variable *wizvars = ast_category_first(wiz);
499         struct ast_sorcery_object *obj = NULL;
500         const char *id = ast_category_get_name(wiz);
501         char new_id[strlen(id) + MAX_ID_SUFFIX];
502         int host_count = AST_VECTOR_SIZE(remote_hosts_vector);
503         int host_counter;
504         RAII_VAR(struct ast_variable *, vars, get_object_variables(wizvars, "identify/"), ast_variables_destroy);
505
506         snprintf(new_id, sizeof(new_id), "%s-identify", id);
507
508         /* If accepting registrations, we don't need an identify. */
509         if (is_variable_true(wizvars, "accepts_registrations")) {
510                 /* If one exists, delete it. */
511                 obj = otw->wizard->retrieve_id(sorcery, otw->wizard_data, "identify", new_id);
512                 if (obj) {
513                         otw->wizard->delete(sorcery, otw->wizard_data, obj);
514                         ao2_ref(obj, -1);
515                 }
516                 return 0;
517         }
518
519         if (!host_count) {
520                 ast_log(LOG_ERROR,
521                         "Wizard '%s' must have 'remote_hosts' if it doesn't accept registrations.\n", id);
522                 return -1;
523         }
524
525         variable_list_append_return(&vars, "endpoint", id);
526         variable_list_append_return(&vars, "@pjsip_wizard", id);
527
528         if (!ast_variable_find_in_list(vars, "match")) {
529                 for (host_counter = 0; host_counter < host_count; host_counter++) {
530                         char *rhost = AST_VECTOR_GET(remote_hosts_vector, host_counter);
531                         char host[strlen(rhost) + 1];
532                         char *colon;
533
534                         /* If there's a :port specified, we have to remove it. */
535                         strcpy(host, rhost); /* Safe */
536                         colon = strchr(host, ':');
537                         if (colon) {
538                                 *colon = '\0';
539                         }
540
541                         variable_list_append_return(&vars, "match", host);
542                 }
543         }
544
545         obj = create_object(sorcery, new_id, "identify", vars);
546         if (!obj) {
547                 return -1;
548         }
549
550         if (otw->wizard->update(sorcery, otw->wizard_data, obj)) {
551                 otw->wizard->create(sorcery, otw->wizard_data, obj);
552         }
553         ao2_ref(obj, -1);
554
555         return 0;
556 }
557
558 static int handle_phoneprov(const struct ast_sorcery *sorcery, struct object_type_wizard *otw,
559         struct ast_category *wiz)
560 {
561         struct ast_variable *wizvars = ast_category_first(wiz);
562         struct ast_sorcery_object *obj = NULL;
563         const char *id = ast_category_get_name(wiz);
564         char new_id[strlen(id) + MAX_ID_SUFFIX];
565         RAII_VAR(struct ast_variable *, vars, get_object_variables(wizvars, "phoneprov/"), ast_variables_destroy);
566
567         snprintf(new_id, sizeof(new_id), "%s-phoneprov", id);
568
569         if (!is_variable_true(wizvars, "has_phoneprov")) {
570                 obj = otw->wizard->retrieve_id(sorcery, otw->wizard_data, "phoneprov", new_id);
571                 if (obj) {
572                         otw->wizard->delete(sorcery, otw->wizard_data, obj);
573                         ao2_ref(obj, -1);
574                 }
575                 return 0;
576         }
577
578         if (!ast_variable_find_in_list(wizvars, "phoneprov/MAC")) {
579                 ast_log(LOG_ERROR,
580                         "Wizard '%s' must have 'phoneprov/MAC' if it has_phoneprov.\n", id);
581                 return -1;
582         }
583
584         variable_list_append_return(&vars, "endpoint", id);
585         variable_list_append_return(&vars, "@pjsip_wizard", id);
586
587         obj = create_object(sorcery, new_id, "phoneprov", vars);
588         if (!obj) {
589                 return -1;
590         }
591
592         if (otw->wizard->update(sorcery, otw->wizard_data, obj)) {
593                 otw->wizard->create(sorcery, otw->wizard_data, obj);
594         }
595         ao2_ref(obj, -1);
596
597         return 0;
598 }
599
600 static int delete_existing_cb(void *obj, void *arg, int flags)
601 {
602         struct object_type_wizard *otw = arg;
603
604         otw->wizard->delete(otw->sorcery, otw->wizard_data, obj);
605
606         return CMP_MATCH;
607 }
608
609 static int handle_registrations(const struct ast_sorcery *sorcery, struct object_type_wizard *otw,
610         struct ast_category *wiz, struct string_vector *remote_hosts_vector)
611 {
612         struct ast_variable *search;
613         struct ast_variable *wizvars = ast_category_first(wiz);
614         const char *id = ast_category_get_name(wiz);
615         const char *server_uri_pattern;
616         const char *client_uri_pattern;
617         const char *transport = ast_variable_find_in_list(wizvars, "transport");
618         const char *username;
619         char new_id[strlen(id) + MAX_ID_SUFFIX];
620         int host_count = AST_VECTOR_SIZE(remote_hosts_vector);
621         int host_counter;
622         RAII_VAR(struct ast_variable *, vars, get_object_variables(wizvars, "registration/"), ast_variables_destroy);
623         RAII_VAR(struct ao2_container *, existing,
624                 ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL), ao2_cleanup);
625
626         if (!existing) {
627                 return -1;
628         }
629
630         /* Find any existing registrations. */
631         search = ast_variable_new("@pjsip_wizard", id, "");
632         if (!search) {
633                 return -1;
634         }
635
636         otw->wizard->retrieve_multiple(sorcery, otw->wizard_data, "registration", existing, search);
637         ast_variables_destroy(search);
638
639         /* If not sending registrations, delete ALL existing registrations for this wizard. */
640         if (!is_variable_true(wizvars, "sends_registrations")) {
641                 if (ao2_container_count(existing) > 0) {
642                         ao2_callback(existing, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, delete_existing_cb, otw);
643                 }
644                 return 0;
645         }
646
647         if (!host_count) {
648                 ast_log(LOG_ERROR, "Wizard '%s' must have 'remote_hosts' if it sends registrations.\n", id);
649                 return -1;
650         }
651
652         variable_list_append_return(&vars, "@pjsip_wizard", id);
653
654         if (!(server_uri_pattern = ast_variable_find_in_list(wizvars, "server_uri_pattern"))) {
655                 server_uri_pattern = "sip:${REMOTE_HOST}";
656         }
657
658         if (!(client_uri_pattern = ast_variable_find_in_list(wizvars, "client_uri_pattern"))) {
659                 client_uri_pattern = "sip:${USERNAME}@${REMOTE_HOST}";
660         }
661
662         if(is_variable_true(wizvars, "sends_auth")) {
663                 username = ast_variable_find_in_list(wizvars, "outbound_auth/username");
664         } else {
665                 username = id;
666         }
667
668
669         /* Unlike aor and identify, we need to create a separate registration object
670          * for each remote host.
671          */
672         for (host_counter = 0; host_counter < host_count; host_counter++) {
673                 struct ast_var_t *rh = ast_var_assign("REMOTE_HOST",
674                         AST_VECTOR_GET(remote_hosts_vector, host_counter));
675                 struct ast_var_t *un = ast_var_assign("USERNAME", username);
676                 struct ast_sorcery_object *obj;
677                 RAII_VAR(struct ast_str *, uri, ast_str_create(64), ast_free);
678                 RAII_VAR(struct varshead *, subst_vars, ast_var_list_create(), ast_var_list_destroy);
679                 RAII_VAR(struct ast_variable *, registration_vars, vars ? ast_variables_dup(vars) : NULL, ast_variables_destroy);
680
681                 AST_VAR_LIST_INSERT_TAIL(subst_vars, rh);
682                 AST_VAR_LIST_INSERT_TAIL(subst_vars, un);
683
684                 if (!ast_strlen_zero(server_uri_pattern)) {
685                         ast_str_substitute_variables_varshead(&uri, 0, subst_vars,
686                                 server_uri_pattern);
687                         variable_list_append_return(&registration_vars, "server_uri", ast_str_buffer(uri));
688                 }
689
690                 if (!ast_strlen_zero(client_uri_pattern)) {
691                         ast_str_reset(uri);
692                         ast_str_substitute_variables_varshead(&uri, 0, subst_vars,
693                                 client_uri_pattern);
694                         variable_list_append_return(&registration_vars, "client_uri", ast_str_buffer(uri));
695                 }
696
697                 if (is_variable_true(wizvars, "sends_auth")) {
698                         snprintf(new_id, sizeof(new_id), "%s-oauth", id);
699                         variable_list_append_return(&registration_vars, "outbound_auth", new_id);
700                 }
701
702                 if (!ast_strlen_zero(transport)) {
703                         variable_list_append_return(&registration_vars, "transport", transport);
704                 }
705
706                 snprintf(new_id, sizeof(new_id), "%s-reg-%d", id, host_counter);
707
708                 obj = create_object(sorcery, new_id, "registration", registration_vars);
709                 if (!obj) {
710                         return -1;
711                 }
712
713                 if (otw->wizard->update(sorcery, otw->wizard_data, obj)) {
714                         otw->wizard->create(sorcery, otw->wizard_data, obj);
715                 }
716                 ao2_ref(obj, -1);
717
718                 /* Unlink it from the 'existing' container.  Any left will be deleted from
719                  * sorcery.  If it wasn't in the existing container, no harm.
720                  */
721                 ao2_callback(existing, OBJ_NODATA | OBJ_UNLINK | OBJ_SEARCH_KEY, ast_sorcery_object_id_compare, new_id);
722         }
723
724         /* If there are any excess registrations, delete them. */
725         if (ao2_container_count(existing) > 0) {
726                 ao2_callback(existing, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, delete_existing_cb, otw);
727         }
728
729         return 0;
730 }
731
732 static int wizard_apply_handler(const struct ast_sorcery *sorcery, struct object_type_wizard *otw,
733         struct ast_category *wiz)
734 {
735         struct ast_variable *wizvars = ast_category_first(wiz);
736         struct string_vector remote_hosts_vector;
737         const char *remote_hosts;
738         int rc = -1;
739
740         AST_VECTOR_INIT(&remote_hosts_vector, 16);
741         remote_hosts = ast_variable_find_in_list(wizvars, "remote_hosts");
742
743         if (!ast_strlen_zero(remote_hosts)) {
744                 char *host;
745                 char *hosts = ast_strdupa(remote_hosts);
746
747                 while ((host = ast_strsep(&hosts, ',', AST_STRSEP_TRIM))) {
748                         AST_VECTOR_APPEND(&remote_hosts_vector, ast_strdup(host));
749                 }
750         }
751
752         ast_debug(4, "%s handler starting.\n", otw->object_type);
753
754         if (!strcmp(otw->object_type, "auth")) {
755                 rc = handle_auths(sorcery, otw, wiz);
756         } else if (!strcmp(otw->object_type, "aor")) {
757                 rc = handle_aor(sorcery, otw, wiz, &remote_hosts_vector);
758         } else if (!strcmp(otw->object_type, "endpoint")) {
759                 rc = handle_endpoint(sorcery, otw, wiz);
760         } else if (!strcmp(otw->object_type, "identify")) {
761                 rc = handle_identify(sorcery, otw, wiz, &remote_hosts_vector);
762         } else if (!strcmp(otw->object_type, "phoneprov")) {
763                 rc = handle_phoneprov(sorcery, otw, wiz);
764         } else if (!strcmp(otw->object_type, "registration")) {
765                 rc = handle_registrations(sorcery, otw, wiz, &remote_hosts_vector);
766         }
767
768         AST_VECTOR_REMOVE_CMP_UNORDERED(&remote_hosts_vector, NULL, NOT_EQUALS, ast_free);
769         AST_VECTOR_FREE(&remote_hosts_vector);
770
771         ast_debug(4, "%s handler complete.  rc: %d\n", otw->object_type, rc);
772
773         return rc;
774 }
775
776 /*
777  * Everything below are the sorcery observers.
778  */
779 static void instance_created_observer(const char *name, struct ast_sorcery *sorcery);
780 static void object_type_loaded_observer(const char *name,
781         const struct ast_sorcery *sorcery, const char *object_type, int reloaded);
782 static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery,
783         const char *object_type, struct ast_sorcery_wizard *wizard,
784         const char *wizard_args, void *wizard_data);
785 static void object_type_registered_observer(const char *name,
786         struct ast_sorcery *sorcery, const char *object_type);
787
788 const static struct ast_sorcery_global_observer global_observer = {
789         .instance_created = instance_created_observer,
790 };
791
792 struct ast_sorcery_instance_observer observer = {
793         .wizard_mapped = wizard_mapped_observer,
794         .object_type_registered = object_type_registered_observer,
795         .object_type_loaded = object_type_loaded_observer,
796 };
797
798 /*! \brief Called after an object type is loaded/reloaded */
799 static void object_type_loaded_observer(const char *name,
800         const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
801 {
802         struct ast_category *category = NULL;
803         struct object_type_wizard *otw = NULL;
804         char *filename = "pjsip_wizard.conf";
805         struct ast_flags flags = { 0 };
806         struct ast_config *cfg;
807
808         if (!strstr("auth aor endpoint identify registration phoneprov", object_type)) {
809                 /* Not interested. */
810                 return;
811         }
812
813         otw = find_wizard(object_type);
814         if (!otw) {
815                 ast_log(LOG_ERROR, "There was no wizard for object type '%s'\n", object_type);
816                 return;
817         }
818
819         if (reloaded && otw->last_config) {
820                 flags.flags = CONFIG_FLAG_FILEUNCHANGED;
821         }
822
823         cfg = ast_config_load2(filename, object_type, flags);
824
825         if (!cfg) {
826                 ast_log(LOG_ERROR, "Unable to load config file '%s'\n", filename);
827                 return;
828         } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
829                 ast_debug(2, "Config file '%s' was unchanged for '%s'.\n", filename, object_type);
830                 return;
831         } else if (cfg == CONFIG_STATUS_FILEINVALID) {
832                 ast_log(LOG_ERROR, "Contents of config file '%s' are invalid and cannot be parsed\n", filename);
833                 return;
834         }
835
836         while ((category = ast_category_browse_filtered(cfg, NULL, category, "type=^wizard$"))) {
837                 const char *id = ast_category_get_name(category);
838                 struct ast_category *last_cat = NULL;
839                 struct ast_variable *change_set = NULL;
840
841                 if (otw->last_config) {
842                         last_cat = ast_category_get(otw->last_config, id, "type=^wizard$");
843                         ast_sorcery_changeset_create(ast_category_first(category), ast_category_first(last_cat), &change_set);
844                         if (last_cat) {
845                                 ast_category_delete(otw->last_config, last_cat);
846                         }
847                 }
848
849                 if (!last_cat || change_set) {
850                         ast_variables_destroy(change_set);
851                         ast_debug(3, "%s: %s(s) for wizard '%s'\n", reloaded ? "Reload" : "Load", object_type, id);
852                         if (wizard_apply_handler(sorcery, otw, category)) {
853                                 ast_log(LOG_ERROR, "Unable to create objects for wizard '%s'\n", id);
854                         }
855                 }
856         }
857
858         if (!otw->last_config) {
859                 otw->last_config = cfg;
860                 return;
861         }
862
863         /* Only wizards that weren't in the new config are left in last_config now so we need to delete
864          * all objects belonging to them.
865          */
866         category = NULL;
867         while ((category = ast_category_browse_filtered(otw->last_config, NULL, category, "type=^wizard$"))) {
868                 const char *id = ast_category_get_name(category);
869                 struct ast_variable *search;
870                 RAII_VAR(struct ao2_container *, existing,
871                         ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL), ao2_cleanup);
872
873                 if (!existing) {
874                         ast_log(LOG_ERROR, "Unable to allocate temporary container.\n");
875                         break;
876                 }
877
878                 search = ast_variable_new("@pjsip_wizard", id, "");
879                 if (!search) {
880                         ast_log(LOG_ERROR, "Unable to allocate memory for vaiable '@pjsip_wizard'.\n");
881                         break;
882                 }
883                 otw->wizard->retrieve_multiple(sorcery, otw->wizard_data, object_type, existing, search);
884                 ast_variables_destroy(search);
885
886                 if (ao2_container_count(existing) > 0) {
887                         ast_debug(3, "Delete on %s: %d %s(s) for wizard: %s\n",
888                                 reloaded ? "Reload" : "Load", ao2_container_count(existing), object_type, id);
889                         ao2_callback(existing, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE,
890                                 delete_existing_cb, otw);
891                 }
892         }
893
894         ast_config_destroy(otw->last_config);
895         otw->last_config = cfg;
896 }
897
898 /*! \brief When each wizard is mapped, save it off to the vector. */
899 static void wizard_mapped_observer(const char *name, struct ast_sorcery *sorcery,
900         const char *object_type, struct ast_sorcery_wizard *wizard,
901         const char *wizard_args, void *wizard_data)
902 {
903         struct object_type_wizard *otw;
904
905         if (!is_one_of(object_type, object_types)) {
906                 /* Not interested. */
907                 return;
908         }
909
910         /* We're only interested in memory wizards with the pjsip_wizard tag. */
911         if (wizard_args && !strcmp(wizard_args, "pjsip_wizard")) {
912                 otw = ast_malloc(sizeof(*otw) + strlen(object_type) + 1);
913                 otw->sorcery = sorcery;
914                 otw->wizard = wizard;
915                 otw->wizard_data = wizard_data;
916                 otw->last_config = NULL;
917                 strcpy(otw->object_type, object_type); /* Safe */
918                 AST_VECTOR_APPEND(&object_type_wizards, otw);
919                 ast_debug(1, "Wizard mapped for object_type '%s'\n", object_type);
920         }
921 }
922
923 /*! \brief When each object type is registered, map a memory wizard to it. */
924 static void object_type_registered_observer(const char *name,
925         struct ast_sorcery *sorcery, const char *object_type)
926 {
927         if (is_one_of(object_type, object_types)) {
928                 ast_sorcery_apply_wizard_mapping(sorcery, object_type, "memory", "pjsip_wizard", 0);
929         }
930 }
931
932 /*! \brief When the res_pjsip instance is created, add an observer to it and initialize the wizard vector.
933  * Since you can't unload res_pjsip, this will only ever be called once.
934  */
935 static void instance_created_observer(const char *name, struct ast_sorcery *sorcery)
936 {
937         if (strcmp(name, "res_pjsip")) {
938                 return;
939         }
940
941         ast_sorcery_instance_observer_add(sorcery, &observer);
942 }
943
944 static int load_module(void)
945 {
946         struct ast_sorcery *sorcery = NULL;
947         int i;
948
949         AST_VECTOR_INIT(&object_type_wizards, 12);
950         ast_sorcery_global_observer_add(&global_observer);
951
952         /* If this module is loading AFTER res_pjsip, we need to manually add the instance observer
953          * and map the wizards because the observers will never get triggered.
954          * The we neeed to schedule a reload.
955          */
956         if (ast_module_check("res_pjsip.so") && ast_sip_get_pjsip_endpoint()) {
957                 sorcery = ast_sip_get_sorcery();
958                 if (sorcery) {
959                         /* Clean up and add the observer. */
960                         ast_sorcery_instance_observer_remove(sorcery, &observer);
961                         ast_sorcery_instance_observer_add(sorcery, &observer);
962
963                         for (i = 0; object_types[i]; i++) {
964                                 ast_sorcery_apply_wizard_mapping(sorcery, object_types[i], "memory",
965                                         "pjsip_wizard", 0);
966                         }
967
968                         ast_module_reload("res_pjsip.so");
969                 }
970         }
971
972         return AST_MODULE_LOAD_SUCCESS;
973 }
974
975 static int unload_module(void)
976 {
977         struct object_type_wizard *otw;
978         int i;
979
980         ast_sorcery_global_observer_remove(&global_observer);
981
982         for (i = 0; object_types[i]; i++) {
983                 RAII_VAR(struct ao2_container *, existing,
984                         ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL), ao2_cleanup);
985
986                 otw = find_wizard(object_types[i]);
987                 if (otw) {
988                         if (otw->sorcery) {
989                                 ast_sorcery_instance_observer_remove(otw->sorcery, &observer);
990                         }
991                         otw->wizard->retrieve_multiple(otw->sorcery, otw->wizard_data, object_types[i], existing, NULL);
992                         ao2_callback(existing, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, delete_existing_cb, otw);
993                 }
994         }
995
996         AST_VECTOR_REMOVE_CMP_UNORDERED(&object_type_wizards, NULL, NOT_EQUALS, OTW_DELETE_CB);
997         AST_VECTOR_FREE(&object_type_wizards);
998
999         return 0;
1000 }
1001
1002 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP Config Wizard",
1003                 .load = load_module,
1004                 .unload = unload_module,
1005                 .load_pri = AST_MODPRI_REALTIME_DRIVER,
1006                 );