Asterisk - The Open Source Telephony Project  18.5.0
res_pjsip_endpoint_identifier_user.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Mark Michelson <[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 /*** MODULEINFO
20  <depend>pjproject</depend>
21  <depend>res_pjsip</depend>
22  <support_level>core</support_level>
23  ***/
24 
25 #include "asterisk.h"
26 
27 #include <pjsip.h>
28 
29 #include "asterisk/res_pjsip.h"
30 #include "asterisk/module.h"
31 
32 static int get_from_header(pjsip_rx_data *rdata, char *username, size_t username_size, char *domain, size_t domain_size)
33 {
34  pjsip_uri *from = rdata->msg_info.from->uri;
35  pjsip_sip_uri *sip_from;
36 
37  if (!PJSIP_URI_SCHEME_IS_SIP(from) && !PJSIP_URI_SCHEME_IS_SIPS(from)) {
38  return -1;
39  }
40  sip_from = (pjsip_sip_uri *) pjsip_uri_get_uri(from);
41  ast_copy_pj_str(username, &sip_from->user, username_size);
42  ast_copy_pj_str(domain, &sip_from->host, domain_size);
43  return 0;
44 }
45 
46 static pjsip_authorization_hdr *get_auth_header(pjsip_rx_data *rdata, char *username,
47  size_t username_size, char *realm, size_t realm_size, pjsip_authorization_hdr *start)
48 {
49  pjsip_authorization_hdr *header;
50 
51  header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, start);
52 
53  if (!header || pj_stricmp2(&header->scheme, "digest")) {
54  return NULL;
55  }
56 
57  ast_copy_pj_str(username, &header->credential.digest.username, username_size);
58  ast_copy_pj_str(realm, &header->credential.digest.realm, realm_size);
59 
60  return header;
61 }
62 
63 static int find_transport_state_in_use(void *obj, void *arg, int flags)
64 {
65  struct ast_sip_transport_state *transport_state = obj;
66  pjsip_rx_data *rdata = arg;
67 
68  if (transport_state->transport == rdata->tp_info.transport
69  || (transport_state->factory
70  && !pj_strcmp(&transport_state->factory->addr_name.host, &rdata->tp_info.transport->local_name.host)
71  && transport_state->factory->addr_name.port == rdata->tp_info.transport->local_name.port)) {
72  return CMP_MATCH;
73  }
74 
75  return 0;
76 }
77 
78 #define DOMAIN_NAME_LEN 255
79 #define USERNAME_LEN 255
80 
81 static struct ast_sip_endpoint *find_endpoint(pjsip_rx_data *rdata, char *endpoint_name,
82  char *domain_name)
83 {
84  struct ast_sip_endpoint *endpoint;
85 
87  struct ast_sip_domain_alias *alias;
89  struct ast_sip_transport_state *transport_state = NULL;
90  struct ast_sip_transport *transport = NULL;
91  char id[DOMAIN_NAME_LEN + USERNAME_LEN + sizeof("@")];
92 
93  /* Attempt to find the endpoint given the name and domain provided */
94  snprintf(id, sizeof(id), "%[email protected]%s", endpoint_name, domain_name);
95  endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id);
96  if (endpoint) {
97  return endpoint;
98  }
99 
100  /* See if an alias exists for the domain provided */
101  alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias",
102  domain_name);
103  if (alias) {
104  snprintf(id, sizeof(id), "%[email protected]%s", endpoint_name, alias->domain);
105  ao2_ref(alias, -1);
106  endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id);
107  if (endpoint) {
108  return endpoint;
109  }
110  }
111 
112  /* See if the transport this came in on has a provided domain */
113  if ((transport_states = ast_sip_get_transport_states())
114  && (transport_state = ao2_callback(transport_states, 0, find_transport_state_in_use, rdata))
115  && (transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id))
116  && !ast_strlen_zero(transport->domain)) {
117  snprintf(id, sizeof(id), "%[email protected]%s", endpoint_name, transport->domain);
118  endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id);
119  }
120  ao2_cleanup(transport);
121  ao2_cleanup(transport_state);
122  ao2_cleanup(transport_states);
123  if (endpoint) {
124  return endpoint;
125  }
126  }
127 
128  /* Fall back to no domain */
129  return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name);
130 }
131 
132 static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata)
133 {
134  char username[USERNAME_LEN + 1];
135  char domain[DOMAIN_NAME_LEN + 1];
136  struct ast_sip_endpoint *endpoint;
137 
138  if (get_from_header(rdata, username, sizeof(username), domain, sizeof(domain))) {
139  return NULL;
140  }
141 
142  /*
143  * We may want to be matched without any user options getting
144  * in the way.
145  */
147 
148  ast_debug(3, "Attempting identify by From username '%s' domain '%s'\n", username, domain);
149 
150  endpoint = find_endpoint(rdata, username, domain);
151  if (!endpoint) {
152  ast_debug(3, "Endpoint not found for From username '%s' domain '%s'\n", username, domain);
153  return NULL;
154  }
156  ast_debug(3, "Endpoint found for '%s' but 'username' method not supported'\n", username);
157  ao2_cleanup(endpoint);
158  return NULL;
159  }
160  ast_debug(3, "Identified by From username '%s' domain '%s'\n", username, domain);
161 
162  return endpoint;
163 }
164 
165 static struct ast_sip_endpoint *auth_username_identify(pjsip_rx_data *rdata)
166 {
167  char username[USERNAME_LEN + 1], realm[DOMAIN_NAME_LEN + 1];
168  struct ast_sip_endpoint *endpoint;
169  pjsip_authorization_hdr *auth_header = NULL;
170 
171  while ((auth_header = get_auth_header(rdata, username, sizeof(username), realm, sizeof(realm),
172  auth_header ? auth_header->next : NULL))) {
173  ast_debug(3, "Attempting identify by Authorization username '%s' realm '%s'\n", username,
174  realm);
175 
176  endpoint = find_endpoint(rdata, username, realm);
177  if (!endpoint) {
178  ast_debug(3, "Endpoint not found for Authentication username '%s' realm '%s'\n",
179  username, realm);
180  ao2_cleanup(endpoint);
181  continue;
182  }
184  ast_debug(3, "Endpoint found for '%s' but 'auth_username' method not supported'\n",
185  username);
186  ao2_cleanup(endpoint);
187  continue;
188  }
189  ast_debug(3, "Identified by Authorization username '%s' realm '%s'\n", username, realm);
190 
191  return endpoint;
192  }
193 
194  return NULL;
195 }
196 
197 
200 };
201 
204 };
205 
206 
207 static int load_module(void)
208 {
209  ast_sip_register_endpoint_identifier_with_name(&username_identifier, "username");
210  ast_sip_register_endpoint_identifier_with_name(&auth_username_identifier, "auth_username");
212 }
213 
214 static int unload_module(void)
215 {
216  ast_sip_unregister_endpoint_identifier(&auth_username_identifier);
217  ast_sip_unregister_endpoint_identifier(&username_identifier);
218  return 0;
219 }
220 
221 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP username endpoint identifier",
222  .support_level = AST_MODULE_SUPPORT_CORE,
223  .load = load_module,
224  .unload = unload_module,
225  .load_pri = AST_MODPRI_CHANNEL_DEPEND - 4,
226  .requires = "res_pjsip",
227 );
#define AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(str)
Truncate the URI user field options string if enabled.
Definition: res_pjsip.h:3036
Asterisk main include file. File version handling, generic pbx functions.
static int unload_module(void)
static int get_from_header(pjsip_rx_data *rdata, char *username, size_t username_size, char *domain, size_t domain_size)
static struct ast_sip_endpoint * auth_username_identify(pjsip_rx_data *rdata)
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
static struct ast_sip_endpoint * username_identify(pjsip_rx_data *rdata)
static int load_module(void)
static struct ao2_container * transport_states
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:5240
struct ast_sip_endpoint *(* identify_endpoint)(pjsip_rx_data *rdata)
Callback used to identify the source of a message. See ast_sip_identify_endpoint for more details...
Definition: res_pjsip.h:998
#define NULL
Definition: resample.c:96
Domain data structure.
Definition: sip.h:888
static struct ast_sip_endpoint_identifier username_identifier
static struct ast_sip_endpoint * find_endpoint(pjsip_rx_data *rdata, char *endpoint_name, char *domain_name)
enum ast_sip_endpoint_identifier_type ident_method
Definition: res_pjsip.h:859
static int find_transport_state_in_use(void *obj, void *arg, int flags)
#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
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
Structure for SIP transport information.
Definition: res_pjsip.h:87
struct pjsip_transport * transport
Transport itself.
Definition: res_pjsip.h:89
#define ao2_ref(o, delta)
Definition: astobj2.h:464
unsigned int ast_sip_get_disable_multi_domain(void)
Retrieve the system setting &#39;disable multi domain&#39;.
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
struct ao2_container * ast_sip_get_transport_states(void)
Retrieves all transport states.
Transport to bind to.
Definition: res_pjsip.h:171
static struct ast_sip_endpoint_identifier auth_username_identifier
struct pjsip_tpfactory * factory
Transport factory.
Definition: res_pjsip.h:91
static pjsip_authorization_hdr * get_auth_header(pjsip_rx_data *rdata, char *username, size_t username_size, char *realm, size_t realm_size, pjsip_authorization_hdr *start)
const ast_string_field domain
Definition: res_pjsip.h:191
An entity responsible for identifying the source of a SIP message.
Definition: res_pjsip.h:993
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",)
const ast_string_field domain
Definition: res_pjsip.h:265
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
int ast_sip_register_endpoint_identifier_with_name(struct ast_sip_endpoint_identifier *identifier, const char *name)
Register a SIP endpoint identifier with a name.
Definition: res_pjsip.c:3431
void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Unregister a SIP endpoint identifier.
Definition: res_pjsip.c:3513
Generic container type.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.