Asterisk - The Open Source Telephony Project  18.5.0
res_pjsip_phoneprov_provider.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2014, Fairview 5 Engineering, LLC
5  *
6  * George Joseph <[email protected]>
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 Phoneprov Configuration Provider
22  *
23  * \author George Joseph <[email protected]>
24  */
25 
26 /*! \li \ref res_pjsip_phoneprov_provider.c uses the configuration file \ref pjsip.conf
27  * \addtogroup configuration_file Configuration Files
28  */
29 
30 /*!
31  * \page pjsip.conf pjsip.conf
32  * \verbinclude pjsip.conf.sample
33  */
34 
35 /*** MODULEINFO
36  <depend>pjproject</depend>
37  <depend>res_pjsip</depend>
38  <depend>res_phoneprov</depend>
39  <support_level>extended</support_level>
40  ***/
41 
42 #include "asterisk.h"
43 
44 #include <pjsip.h>
45 
46 #include "asterisk/res_pjsip.h"
47 #include "asterisk/module.h"
48 #include "asterisk/sorcery.h"
49 #include "asterisk/phoneprov.h"
51 
52 /*** DOCUMENTATION
53  <configInfo name="res_pjsip_phoneprov_provider" language="en_US">
54  <synopsis>Module that integrates res_pjsip with res_phoneprov.</synopsis>
55  <description><para>
56  <emphasis>PJSIP Phoneprov Provider</emphasis>
57  </para>
58  <para>This module creates the integration between <literal>res_pjsip</literal> and
59  <literal>res_phoneprov</literal>.
60  </para>
61  <para>Each user to be integrated requires a <literal>phoneprov</literal>
62  section defined in <filename>pjsip.conf</filename>. Each section identifies
63  the endpoint associated with the user and any other name/value pairs to be passed
64  on to res_phoneprov's template substitution. Only <literal>MAC</literal> and
65  <literal>PROFILE</literal> variables are required. Any other variables
66  supplied will be passed through.</para>
67  <para> </para>
68  <para>Example:</para>
69  <para>[1000]</para>
70  <para>type = phoneprovr</para>
71  <para>endpoint = ep1000</para>
72  <para>MAC = deadbeef4dad</para>
73  <para>PROFILE = grandstream2</para>
74  <para>LINEKEYS = 2</para>
75  <para>LINE = 1</para>
76  <para>OTHERVAR = othervalue</para>
77  <para> </para>
78  <para>The following variables are automatically defined if an endpoint
79  is defined for the user:</para>
80  <enumlist>
81  <enum name="USERNAME"><para>Source: The user_name defined in the first auth reference
82  in the endpoint.</para></enum>
83  <enum name="SECRET"><para>Source: The user_pass defined in the first auth reference
84  in the endpoint.</para></enum>
85  <enum name="CALLERID"><para>Source: The number part of the callerid defined in
86  the endpoint.</para></enum>
87  <enum name="DISPLAY_NAME"><para>Source: The name part of the callerid defined in
88  the endpoint.</para></enum>
89  <enum name="LABEL"><para>Source: The id of the phoneprov section.</para></enum>
90  </enumlist>
91  <para> </para>
92  <para>In addition to the standard variables, the following are also automatically defined:</para>
93  <enumlist>
94  <enum name="ENDPOINT_ID"><para>Source: The id of the endpoint.</para></enum>
95  <enum name="TRANSPORT_ID"><para>Source: The id of the transport used by the endpoint.</para></enum>
96  <enum name="AUTH_ID"><para>Source: The id of the auth used by the endpoint.</para></enum>
97  </enumlist>
98  <para> </para>
99  <para>All other template substitution variables must be explicitly defined in the
100  phoneprov_default or phoneprov sections.</para>
101  </description>
102 
103  <configFile name="pjsip.conf">
104  <configObject name="phoneprov">
105  <synopsis>Provides variables for each user.</synopsis>
106  <configOption name="type">
107  <synopsis>Must be of type 'phoneprov'.</synopsis>
108  </configOption>
109  <configOption name="endpoint">
110  <synopsis>The endpoint from which variables will be retrieved.</synopsis>
111  </configOption>
112  <configOption name="MAC">
113  <synopsis>The mac address for this user. (required)</synopsis>
114  </configOption>
115  <configOption name="PROFILE">
116  <synopsis>The phoneprov profile to use for this user. (required)</synopsis>
117  </configOption>
118  <configOption name="*">
119  <synopsis>Other name/value pairs to be passed through for use in templates.</synopsis>
120  </configOption>
121  </configObject>
122  </configFile>
123  </configInfo>
124  ***/
125 
126 static struct ast_sorcery *sorcery;
127 
128 /*! \brief Structure for a phoneprov object */
129 struct phoneprov {
130  SORCERY_OBJECT(details);
131  struct varshead *vars;
132 };
133 
134 /*! \brief Destructor function for phoneprov */
135 static void phoneprov_destroy(void *obj)
136 {
137  struct phoneprov *pp = obj;
138  char *mac = ast_var_find(pp->vars, "MAC");
139 
140  if (mac) {
142  }
143 
145 }
146 
147 /*! \brief Allocator for phoneprov */
148 static void *phoneprov_alloc(const char *name)
149 {
150  struct phoneprov *pp = ast_sorcery_generic_alloc(sizeof(*pp), phoneprov_destroy);
151 
152  if (!pp || !(pp->vars = ast_var_list_create())) {
153  ast_log(LOG_ERROR, "Unable to allocate memory for phoneprov structure %s\n",
154  name);
155  ao2_cleanup(pp);
156  return NULL;
157  }
158 
159  return pp;
160 }
161 
162 /*! \brief Helper that creates an ast_var_t and inserts it into the list */
163 static int assign_and_insert(const char *name, const char *value, struct varshead *vars)
164 {
165  struct ast_var_t *var;
166 
167  if (ast_strlen_zero(name) || !vars) {
168  return -1;
169  }
170 
171  /* Just ignore if the value is NULL or empty */
172  if (ast_strlen_zero(value)) {
173  return 0;
174  }
175 
176  var = ast_var_assign(name, value);
177  if (!var) {
178  ast_log(LOG_ERROR, "Could not allocate variable memory for variable.\n");
179  return -1;
180  }
181  AST_VAR_LIST_INSERT_TAIL(vars, var);
182 
183  return 0;
184 }
185 
186 /*! \brief Adds a config name/value pair to the phoneprov object */
187 static int aco_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
188 {
189  struct phoneprov *pp = obj;
190 
191  return assign_and_insert(var->name, var->value, pp->vars);
192 }
193 
194 /*! \brief Converts the phoneprov varlist to an ast_variable list */
195 static int fields_handler(const void *obj, struct ast_variable **fields)
196 {
197  const struct phoneprov *pp = obj;
198  struct ast_var_t *pvar;
199  struct ast_variable *head = NULL;
200  struct ast_variable *tail = NULL;
201  struct ast_variable *var;
202 
203  AST_VAR_LIST_TRAVERSE(pp->vars, pvar) {
204  var = ast_variable_new(pvar->name, pvar->value, "");
205  if (!var) {
206  ast_variables_destroy(head);
207  return -1;
208  }
209  if (!head) {
210  head = var;
211  tail = var;
212  continue;
213  }
214  tail->next = var;
215  tail = var;
216  }
217 
218  *fields = head;
219 
220  return 0;
221 }
222 
223 static int load_endpoint(const char *id, const char *endpoint_name, struct varshead *vars,
224  char *port_string)
225 {
226  struct ast_sip_auth *auth;
227  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
228  RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup);
229  const char *auth_name;
230 
231  *port_string = '\0';
232 
233  /* We need to use res_pjsip's sorcery instance instead of our own to
234  * get endpoint and auth.
235  */
236  endpoint = ast_sorcery_retrieve_by_id(sorcery, "endpoint",
237  endpoint_name);
238  if (!endpoint) {
239  ast_log(LOG_ERROR, "phoneprov %s contained invalid endpoint %s.\n", id,
240  endpoint_name);
241  return -1;
242  }
243 
244  assign_and_insert("ENDPOINT_ID", endpoint_name, vars);
245  assign_and_insert("TRANSPORT_ID", endpoint->transport, vars);
246 
247  if (endpoint->id.self.number.valid && !ast_strlen_zero(endpoint->id.self.number.str)) {
249  endpoint->id.self.number.str, vars);
250  }
251 
252  if (endpoint->id.self.name.valid && !ast_strlen_zero(endpoint->id.self.name.str)) {
255  endpoint->id.self.name.str, vars);
256  }
257 
258  transport = ast_sorcery_retrieve_by_id(sorcery, "transport",
259  endpoint->transport);
260  if (!transport) {
261  ast_log(LOG_ERROR, "Endpoint %s contained invalid transport %s.\n", endpoint_name,
262  endpoint->transport);
263  return -1;
264  }
265  snprintf(port_string, 6, "%d", pj_sockaddr_get_port(&transport->host));
266 
267  if (!AST_VECTOR_SIZE(&endpoint->inbound_auths)) {
268  return 0;
269  }
270  auth_name = AST_VECTOR_GET(&endpoint->inbound_auths, 0);
271 
272  auth = ast_sorcery_retrieve_by_id(sorcery, "auth", auth_name);
273  if (!auth) {
274  ast_log(LOG_ERROR, "phoneprov %s contained invalid auth %s.\n", id, auth_name);
275  return -1;
276  }
277 
278  assign_and_insert("AUTH_ID", auth_name, vars);
280  auth->auth_user, vars);
282  auth->auth_pass, vars);
283  ao2_ref(auth, -1);
284 
285  return 0;
286 }
287 
288 /*! \brief Callback that validates the phoneprov object */
289 static void users_apply_handler(struct phoneprov *pp)
290 {
291  const char *id = ast_sorcery_object_get_id(pp);
292  const char *endpoint_name;
293  char port_string[6];
294 
295  if (!ast_var_find(pp->vars,
297  ast_log(LOG_ERROR, "phoneprov %s must contain a MAC entry.\n", id);
298  return;
299  }
300 
301  if (!ast_var_find(pp->vars,
303  ast_log(LOG_ERROR, "phoneprov %s must contain a PROFILE entry.\n", id);
304  return;
305  }
306 
307  endpoint_name = ast_var_find(pp->vars, "endpoint");
308  if (endpoint_name) {
309  if (load_endpoint(id, endpoint_name, pp->vars, port_string)) {
310  return;
311  }
312  }
313 
314  if (!ast_var_find(pp->vars,
318  pp->vars);
319  }
320 
321  if (!ast_var_find(pp->vars,
324  id, pp->vars);
325  }
326 
327  if (!ast_var_find(pp->vars,
329  assign_and_insert("SERVER_PORT", S_OR(port_string, "5060"), pp->vars);
330  }
331 
332  if (!ast_var_find(pp->vars,
334  ast_log(LOG_ERROR, "phoneprov %s didn't contain a PROFILE entry.\n", id);
335  }
336 
338 
339  return;
340 }
341 
342 /*! \brief Callback that loads the users from phoneprov sections */
343 static int load_users(void)
344 {
345  struct ao2_container *users;
346  struct ao2_iterator i;
347  struct phoneprov *pp;
348 
349  ast_sorcery_reload_object(sorcery, "phoneprov");
350 
351  users = ast_sorcery_retrieve_by_fields(sorcery, "phoneprov",
353  if (!users) {
354  return 0;
355  }
356 
357  i = ao2_iterator_init(users, 0);
358  while ((pp = ao2_iterator_next(&i))) {
360  ao2_ref(pp, -1);
361  }
363  ao2_ref(users, -1);
364 
365  return 0;
366 }
367 
368 static int load_module(void)
369 {
370  sorcery = ast_sip_get_sorcery();
371 
372  ast_sorcery_apply_config(sorcery, "res_pjsip_phoneprov_provider");
373  ast_sorcery_apply_default(sorcery, "phoneprov", "config",
374  "pjsip.conf,criteria=type=phoneprov");
375 
376  ast_sorcery_object_register(sorcery, "phoneprov", phoneprov_alloc, NULL,
377  NULL);
378 
379  ast_sorcery_object_field_register(sorcery, "phoneprov", "type", "", OPT_NOOP_T, 0,
380  0);
381  ast_sorcery_object_fields_register(sorcery, "phoneprov", "^", aco_handler,
383 
384  ast_sorcery_load_object(sorcery, "phoneprov");
385 
387  ast_log(LOG_ERROR, "Unable to register pjsip phoneprov provider.\n");
389  }
390 
392 }
393 
394 static int unload_module(void)
395 {
397 
398  return 0;
399 }
400 
401 static int reload_module(void)
402 {
404 
406  ast_log(LOG_ERROR, "Unable to register pjsip phoneprov provider.\n");
408  }
409 
410  return 0;
411 }
412 
413 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Phoneprov Provider",
414  .support_level = AST_MODULE_SUPPORT_EXTENDED,
415  .load = load_module,
417  .unload = unload_module,
418  .load_pri = AST_MODPRI_APP_DEPEND,
419  .requires = "res_pjsip,res_phoneprov",
420 );
struct ast_variable * next
Asterisk main include file. File version handling, generic pbx functions.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
struct varshead * vars
static int load_endpoint(const char *id, const char *endpoint_name, struct varshead *vars, char *port_string)
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
Perform no matching, return all objects.
Definition: sorcery.h:123
int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
Register a regex for multiple fields within an object.
Definition: sorcery.c:1160
Full structure for sorcery.
Definition: sorcery.c:230
Type for a default handler that should do nothing.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_sorcery_apply_config(sorcery, name)
Definition: sorcery.h:456
Return all matching objects.
Definition: sorcery.h:120
#define NULL
Definition: resample.c:96
void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to load persistent objects.
Definition: sorcery.c:1393
int value
Definition: syslog.c:37
#define ast_strlen_zero(foo)
Definition: strings.h:52
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
int ast_phoneprov_provider_register(char *provider_name, ast_phoneprov_load_users_cb load_users)
Registers a config provider to phoneprov.
#define ast_log
Definition: astobj2.c:42
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
void ast_phoneprov_provider_unregister(char *provider_name)
Unegisters a config provider from phoneprov and frees its resources.
#define ao2_ref(o, delta)
Definition: astobj2.h:464
SORCERY_OBJECT(details)
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
#define ast_variable_new(name, value, filename)
static void phoneprov_destroy(void *obj)
Destructor function for phoneprov.
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:838
char name[0]
Definition: chanvars.h:31
#define LOG_ERROR
Definition: logger.h:285
Transport to bind to.
Definition: res_pjsip.h:171
static int unload_module(void)
char * value
Definition: chanvars.h:30
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:477
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
struct ao2_container * users
static int assign_and_insert(const char *name, const char *value, struct varshead *vars)
Helper that creates an ast_var_t and inserts it into the list.
static const char name[]
Definition: cdr_mysql.c:74
char * ast_var_find(const struct varshead *head, const char *name)
Definition: chanvars.c:85
static int reload(void)
Definition: cdr_mysql.c:741
#define ast_var_assign(name, value)
Definition: chanvars.h:40
const ast_string_field auth_pass
Definition: res_pjsip.h:452
static void users_apply_handler(struct phoneprov *pp)
Callback that validates the phoneprov object.
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
Structure for a phoneprov object.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition: sorcery.c:1897
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
static void * phoneprov_alloc(const char *name)
Allocator for phoneprov.
struct varshead * ast_var_list_create(void)
Definition: chanvars.c:97
int ast_phoneprov_add_extension(char *provider_name, struct varshead *vars)
Adds an extension.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
static struct ast_sorcery * sorcery
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define AST_MODULE
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
static int load_users(void)
Callback that loads the users from phoneprov sections.
const char * ast_phoneprov_std_variable_lookup(enum ast_phoneprov_std_variables var)
Returns the string respresentation of a phoneprov standard variable.
static int aco_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Adds a config name/value pair to the phoneprov object.
Generic container type.
static int fields_handler(const void *obj, struct ast_variable **fields)
Converts the phoneprov varlist to an ast_variable list.
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
#define AST_VAR_LIST_TRAVERSE(head, var)
Definition: chanvars.h:49
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
void ast_phoneprov_delete_extension(char *provider_name, char *macaddress)
Deletes an extension.
Asterisk module definitions.
void ast_var_list_destroy(struct varshead *head)
Definition: chanvars.c:109
static int reload_module(void)
static void AST_VAR_LIST_INSERT_TAIL(struct varshead *head, struct ast_var_t *var)
Definition: chanvars.h:51
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
const ast_string_field auth_user
Definition: res_pjsip.h:450
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects.
Definition: sorcery.c:1442
Sorcery Data Access Layer API.
static int load_module(void)