Merge lp:~ari-tczew/ubuntu/saucy/asterisk/lp-1205644 into lp:ubuntu/saucy/asterisk
- Saucy (13.10)
- lp-1205644
- Merge into saucy
Proposed by
Artur Rona
Status: | Merged |
---|---|
Merge reported by: | Artur Rona |
Merged at revision: | not available |
Proposed branch: | lp:~ari-tczew/ubuntu/saucy/asterisk/lp-1205644 |
Merge into: | lp:ubuntu/saucy/asterisk |
Diff against target: |
1735 lines (+1684/-2) 8 files modified
debian/changelog (+49/-0) debian/patches/AST-2012-014 (+162/-0) debian/patches/AST-2012-015 (+1012/-0) debian/patches/AST-2013-002 (+55/-0) debian/patches/AST-2013-003 (+370/-0) debian/patches/armhf-fixes (+1/-2) debian/patches/bluetooth_bind (+30/-0) debian/patches/series (+5/-0) |
To merge this branch: | bzr merge lp:~ari-tczew/ubuntu/saucy/asterisk/lp-1205644 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Holbach (community) | Approve | ||
Review via email: mp+177296@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2013-06-13 13:23:50 +0000 |
3 | +++ debian/changelog 2013-07-28 21:58:23 +0000 |
4 | @@ -1,3 +1,52 @@ |
5 | +asterisk (1:1.8.13.1~dfsg-3ubuntu1) saucy; urgency=low |
6 | + |
7 | + * Merge from Debian unstable. (LP: #1205644) Remaining changes: |
8 | + - debian/asterisk.init: |
9 | + + chown /dev/dahdi |
10 | + - debian/control, debian/rules: |
11 | + + Enable Hardening Wrapper (PIE and BIND_NOW). |
12 | + + Build against libical 1.0. |
13 | + - debian/patches/armhf-fixes: |
14 | + + Fix FTBFS on armhf. |
15 | + * Fixed security issues: |
16 | + - CVE-2012-5976 (LP: #1097687) |
17 | + - CVE-2012-5977 (LP: #1097691) |
18 | + - CVE-2013-2686 |
19 | + - CVE-2013-2264 |
20 | + |
21 | + -- Artur Rona <ari-tczew@tlen.pl> Sat, 27 Jul 2013 14:56:17 +0200 |
22 | + |
23 | +asterisk (1:1.8.13.1~dfsg-3) unstable; urgency=high |
24 | + |
25 | + * Rewrtote sip.conf parts of AST-2012-014: dropped patches |
26 | + fix-sip-tcp-no-FILE and fix-sip-tls-leak. |
27 | + * Reverting other changes rejected by the release team: README.Debian, |
28 | + powerpcspe and fix_xmpp_19532 dropped (#545272 and #701505 reopened). |
29 | + |
30 | + -- Tzafrir Cohen <tzafrir@debian.org> Tue, 09 Apr 2013 13:23:07 +0300 |
31 | + |
32 | +asterisk (1:1.8.13.1~dfsg-2) unstable; urgency=high |
33 | + |
34 | + * Patches backported from Asterisk 1.8.19.1 (Closes: #697230): |
35 | + - Patch AST-2012-014 (CVE-2012-5976) - fixes Crashes due to large stack |
36 | + allocations when using TCP. |
37 | + The following two fixes were also pulled in order to easily apply it: |
38 | + - Patch fix-sip-tcp-no-FILE - Switch to reading with a recv loop |
39 | + - Patch fix-sip-tls-leak - Memory leak in the SIP TLS code |
40 | + - Patch AST-2012-015 (CVE-2012-5977) - Denial of Service Through |
41 | + Exploitation of Device State Caching |
42 | + * Patch powerpcspe: Fix OSARCH for powerpcspe (Closes: #701505). |
43 | + * README.Debian: document running the testsuite. |
44 | + * Patch fix_xmpp_19532: fix a crash of the XMPP code (Closes: #545272). |
45 | + * Patches backported from Asterisk 1.8.20.2 (Closes: #704114): |
46 | + - Patch AST-2013-002 (CVE-2013-2686): Prevent DoS in HTTP server with |
47 | + a large POST. |
48 | + - Patch AST-2013-003 (CVE-2013-2264): Prevent username disclosure in |
49 | + SIP channel driver. |
50 | + * Patch bluetooth_bind - fix breakage of chan_mobile (Closes: #614786). |
51 | + |
52 | + -- Tzafrir Cohen <tzafrir@debian.org> Sat, 06 Apr 2013 14:15:41 +0300 |
53 | + |
54 | asterisk (1:1.8.13.1~dfsg-1ubuntu4) saucy; urgency=low |
55 | |
56 | * Build against libical 1.0 |
57 | |
58 | === added file 'debian/patches/AST-2012-014' |
59 | --- debian/patches/AST-2012-014 1970-01-01 00:00:00 +0000 |
60 | +++ debian/patches/AST-2012-014 2013-07-28 21:58:23 +0000 |
61 | @@ -0,0 +1,162 @@ |
62 | +From: Matthew Jordan <mjordan@digium.com> |
63 | +Date: Wed, 2 Jan 2013 15:16:10 +0000 |
64 | +Subject: Resolve crashes due to large stack allocations when using TCP |
65 | +Origin: http://svnview.digium.com/svn/asterisk?view=rev&rev=378269 |
66 | +CVE: CVE-2012-5976 |
67 | +Bug: https://issues.asterisk.org/jira/browse/ASTERISK-20658 |
68 | + |
69 | +Asterisk had several places where messages received over various network |
70 | +transports may be copied in a single stack allocation. In the case of TCP, |
71 | +since multiple packets in a stream may be concatenated together, this can |
72 | +lead to large allocations that overflow the stack. |
73 | + |
74 | +This patch modifies those portions of Asterisk using TCP to either |
75 | +favor heap allocations or use an upper bound to ensure that the stack will not |
76 | +overflow: |
77 | + * For SIP, the allocation now has an upper limit |
78 | + * For HTTP, the allocation is now a heap allocation instead of a stack |
79 | + allocation |
80 | + * For XMPP (in res_jabber), the allocation has been eliminated since it was |
81 | + unnecesary. |
82 | + |
83 | +Note that the HTTP portion of this issue was independently found by Brandon |
84 | +Edwards of Exodus Intelligence. |
85 | + |
86 | +Reported by: wdoekes, Brandon Edwards |
87 | +Tested by: mmichelson, wdoekes |
88 | +See also: http://downloads.asterisk.org/pub/security/AST-2012-014.html |
89 | + |
90 | +--- |
91 | + channels/chan_sip.c | 58 +++++++++++++++++++++++++++++++------------- |
92 | + channels/sip/include/sip.h | 1 + |
93 | + main/http.c | 20 ++++++++++++--- |
94 | + res/res_jabber.c | 5 ++-- |
95 | + 4 files changed, 60 insertions(+), 24 deletions(-) |
96 | + |
97 | +--- a/channels/chan_sip.c |
98 | ++++ b/channels/chan_sip.c |
99 | +@@ -2504,6 +2504,7 @@ static void *_sip_tcp_helper_thread(stru |
100 | + int res, cl, timeout = -1, authenticated = 0, flags, after_poll = 0, need_poll = 1; |
101 | + time_t start; |
102 | + struct sip_request req = { 0, } , reqcpy = { 0, }; |
103 | ++ size_t datalen; |
104 | + struct sip_threadinfo *me = NULL; |
105 | + char buf[1024] = ""; |
106 | + struct pollfd fds[2] = { { 0 }, { 0 }, }; |
107 | +@@ -2640,8 +2641,9 @@ static void *_sip_tcp_helper_thread(stru |
108 | + } |
109 | + req.socket.fd = tcptls_session->fd; |
110 | + |
111 | ++ datalen = ast_str_strlen(req.data); |
112 | + /* Read in headers one line at a time */ |
113 | +- while (ast_str_strlen(req.data) < 4 || strncmp(REQ_OFFSET_TO_STR(&req, data->used - 4), "\r\n\r\n", 4)) { |
114 | ++ while (datalen < 4 || strncmp(REQ_OFFSET_TO_STR(&req, data->used - 4), "\r\n\r\n", 4)) { |
115 | + if (!tcptls_session->client && !authenticated ) { |
116 | + if ((timeout = sip_check_authtimeout(start)) < 0) { |
117 | + goto cleanup; |
118 | +@@ -2688,6 +2690,14 @@ static void *_sip_tcp_helper_thread(stru |
119 | + goto cleanup; |
120 | + } |
121 | + ast_str_append(&req.data, 0, "%s", buf); |
122 | ++ datalen = ast_str_strlen(req.data); |
123 | ++ if (datalen > SIP_MAX_PACKET_SIZE) { |
124 | ++ ast_log(LOG_WARNING, "Rejecting SIP %s packet from '%s' because way too large: %zu\n", |
125 | ++ tcptls_session->ssl ? "SSL" : "TCP", |
126 | ++ ast_sockaddr_stringify(&tcptls_session->remote_address), |
127 | ++ datalen); |
128 | ++ goto cleanup; |
129 | ++ } |
130 | + } |
131 | + copy_request(&reqcpy, &req); |
132 | + parse_request(&reqcpy); |
133 | +--- a/channels/sip/include/sip.h |
134 | ++++ b/channels/sip/include/sip.h |
135 | +@@ -96,6 +96,7 @@ |
136 | + |
137 | + #define SIP_MAX_HEADERS 64 /*!< Max amount of SIP headers to read */ |
138 | + #define SIP_MAX_LINES 256 /*!< Max amount of lines in SIP attachment (like SDP) */ |
139 | ++#define SIP_MAX_PACKET_SIZE 20480 /*!< Max SIP packet size */ |
140 | + #define SIP_MIN_PACKET 4096 /*!< Initialize size of memory to allocate for packets */ |
141 | + #define MAX_HISTORY_ENTRIES 50 /*!< Max entires in the history list for a sip_pvt */ |
142 | + |
143 | +--- a/main/http.c |
144 | ++++ b/main/http.c |
145 | +@@ -622,6 +622,7 @@ struct ast_variable *ast_http_get_post_v |
146 | + int content_length = 0; |
147 | + struct ast_variable *v, *post_vars=NULL, *prev = NULL; |
148 | + char *buf, *var, *val; |
149 | ++ int res; |
150 | + |
151 | + for (v = headers; v; v = v->next) { |
152 | + if (!strcasecmp(v->name, "Content-Type")) { |
153 | +@@ -634,21 +635,27 @@ struct ast_variable *ast_http_get_post_v |
154 | + |
155 | + for (v = headers; v; v = v->next) { |
156 | + if (!strcasecmp(v->name, "Content-Length")) { |
157 | +- content_length = atoi(v->value) + 1; |
158 | ++ content_length = atoi(v->value); |
159 | + break; |
160 | + } |
161 | + } |
162 | + |
163 | +- if (!content_length) { |
164 | ++ if (content_length <= 0) { |
165 | + return NULL; |
166 | + } |
167 | + |
168 | +- if (!(buf = alloca(content_length))) { |
169 | ++ buf = ast_malloc(content_length + 1); |
170 | ++ if (!buf) { |
171 | + return NULL; |
172 | + } |
173 | +- if (!fgets(buf, content_length, ser->f)) { |
174 | +- return NULL; |
175 | ++ |
176 | ++ res = fread(buf, 1, content_length, ser->f); |
177 | ++ if (res < content_length) { |
178 | ++ /* Error, distinguishable by ferror() or feof(), but neither |
179 | ++ * is good. */ |
180 | ++ goto done; |
181 | + } |
182 | ++ buf[content_length] = '\0'; |
183 | + |
184 | + while ((val = strsep(&buf, "&"))) { |
185 | + var = strsep(&val, "="); |
186 | +@@ -667,6 +674,9 @@ struct ast_variable *ast_http_get_post_v |
187 | + prev = v; |
188 | + } |
189 | + } |
190 | ++ |
191 | ++done: |
192 | ++ ast_free(buf); |
193 | + return post_vars; |
194 | + } |
195 | + |
196 | +--- a/res/res_jabber.c |
197 | ++++ b/res/res_jabber.c |
198 | +@@ -768,7 +768,7 @@ static struct ast_custom_function jabber |
199 | + */ |
200 | + static int acf_jabberreceive_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen) |
201 | + { |
202 | +- char *aux = NULL, *parse = NULL; |
203 | ++ char *parse = NULL; |
204 | + int timeout; |
205 | + int jidlen, resourcelen; |
206 | + struct timeval start; |
207 | +@@ -885,7 +885,7 @@ static int acf_jabberreceive_read(struct |
208 | + continue; |
209 | + } |
210 | + found = 1; |
211 | +- aux = ast_strdupa(tmp->message); |
212 | ++ ast_copy_string(buf, tmp->message, buflen); |
213 | + AST_LIST_REMOVE_CURRENT(list); |
214 | + aji_message_destroy(tmp); |
215 | + break; |
216 | +@@ -910,7 +910,6 @@ static int acf_jabberreceive_read(struct |
217 | + ast_log(LOG_NOTICE, "Timed out : no message received from %s\n", args.jid); |
218 | + return -1; |
219 | + } |
220 | +- ast_copy_string(buf, aux, buflen); |
221 | + |
222 | + return 0; |
223 | + } |
224 | |
225 | === added file 'debian/patches/AST-2012-015' |
226 | --- debian/patches/AST-2012-015 1970-01-01 00:00:00 +0000 |
227 | +++ debian/patches/AST-2012-015 2013-07-28 21:58:23 +0000 |
228 | @@ -0,0 +1,1012 @@ |
229 | +From: Matthew Jordan <mjordan@digium.com> |
230 | +Date: Wed, 2 Jan 2013 16:54:20 +0000 |
231 | +Subject: Prevent exhaustion of system resources through exploitation of event cache |
232 | +CVE: CVE-2012-5977 |
233 | +Origin: http://svnview.digium.com/svn/asterisk?view=rev&rev=378303 |
234 | +Bug: https://issues.asterisk.org/jira/browse/ASTERISK-20175 |
235 | + |
236 | +Asterisk maintains an internal cache for devices in the event subsystem. The |
237 | +device state cache holds the state of each device known to Asterisk, such that |
238 | +consumers of device state information can query for the last known state for |
239 | +a particular device, even if it is not part of an active call. The concept of |
240 | +a device in Asterisk can include entities that do not have a physical |
241 | +representation. One way that this occurred was when anonymous calls are allowed |
242 | +in Asterisk. A device was automatically created and stored in the cache for |
243 | +each anonymous call that occurred; this was possible in the SIP and IAX2 |
244 | +channel drivers and through channel drivers that utilized the |
245 | +res_jabber/res_xmpp resource modules (Gtalk, Jingle, and Motif). These devices |
246 | +are never removed from the system, allowing anonymous calls to potentially |
247 | +exhaust a system's resources. |
248 | + |
249 | +This patch changes the event cache subsystem and device state management to |
250 | +no longer cache devices that are not associated with a physical entity. |
251 | + |
252 | +Reported by: Russell Bryant, Leif Madsen, Joshua Colp |
253 | +Tested by: kmoore |
254 | +See also: http://downloads.asterisk.org/pub/security/AST-2012-015.html |
255 | + |
256 | +--- |
257 | + apps/app_confbridge.c | 4 +-- |
258 | + apps/app_meetme.c | 16 +++++------ |
259 | + channels/chan_agent.c | 12 ++++---- |
260 | + channels/chan_dahdi.c | 7 +++-- |
261 | + channels/chan_iax2.c | 31 +++++++++++--------- |
262 | + channels/chan_local.c | 3 ++ |
263 | + channels/chan_sip.c | 18 +++++++----- |
264 | + channels/chan_skinny.c | 16 +++++------ |
265 | + funcs/func_devstate.c | 6 ++-- |
266 | + include/asterisk/channel.h | 6 ++++ |
267 | + include/asterisk/devicestate.h | 16 +++++++++-- |
268 | + include/asterisk/event_defs.h | 8 +++++- |
269 | + main/channel.c | 5 ++-- |
270 | + main/devicestate.c | 51 +++++++++++++++++++++------------ |
271 | + main/event.c | 1 + |
272 | + main/features.c | 2 +- |
273 | + res/res_calendar.c | 8 +++--- |
274 | + res/res_jabber.c | 61 ++++++++++++++++++++++++++++++---------- |
275 | + 18 files changed, 177 insertions(+), 94 deletions(-) |
276 | + |
277 | +--- a/apps/app_confbridge.c |
278 | ++++ b/apps/app_confbridge.c |
279 | +@@ -486,7 +486,7 @@ static struct conference_bridge *join_co |
280 | + |
281 | + /* Set the device state for this conference */ |
282 | + if (conference_bridge->users == 1) { |
283 | +- ast_devstate_changed(AST_DEVICE_INUSE, "confbridge:%s", conference_bridge->name); |
284 | ++ ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", conference_bridge->name); |
285 | + } |
286 | + |
287 | + /* If the caller is a marked user or is waiting for a marked user to enter pass 'em off, otherwise pass them off to do regular joining stuff */ |
288 | +@@ -568,7 +568,7 @@ static void leave_conference_bridge(str |
289 | + } |
290 | + } else { |
291 | + /* Set device state to "not in use" */ |
292 | +- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "confbridge:%s", conference_bridge->name); |
293 | ++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "confbridge:%s", conference_bridge->name); |
294 | + |
295 | + ao2_unlink(conference_bridges, conference_bridge); |
296 | + } |
297 | +--- a/apps/app_meetme.c |
298 | ++++ b/apps/app_meetme.c |
299 | +@@ -2489,7 +2489,7 @@ static int conf_run(struct ast_channel * |
300 | + |
301 | + /* This device changed state now - if this is the first user */ |
302 | + if (conf->users == 1) |
303 | +- ast_devstate_changed(AST_DEVICE_INUSE, "meetme:%s", conf->confno); |
304 | ++ ast_devstate_changed(AST_DEVICE_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno); |
305 | + |
306 | + ast_mutex_unlock(&conf->playlock); |
307 | + |
308 | +@@ -3783,7 +3783,7 @@ bailoutandtrynormal: |
309 | + |
310 | + /* Change any states */ |
311 | + if (!conf->users) { |
312 | +- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "meetme:%s", conf->confno); |
313 | ++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, (conf->isdynamic ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), "meetme:%s", conf->confno); |
314 | + } |
315 | + |
316 | + /* Return the number of seconds the user was in the conf */ |
317 | +@@ -5199,8 +5199,8 @@ static void sla_change_trunk_state(const |
318 | + || trunk_ref == exclude) |
319 | + continue; |
320 | + trunk_ref->state = state; |
321 | +- ast_devstate_changed(sla_state_to_devstate(state), |
322 | +- "SLA:%s_%s", station->name, trunk->name); |
323 | ++ ast_devstate_changed(sla_state_to_devstate(state), AST_DEVSTATE_CACHABLE, |
324 | ++ "SLA:%s_%s", station->name, trunk->name); |
325 | + break; |
326 | + } |
327 | + } |
328 | +@@ -5698,8 +5698,8 @@ static void sla_handle_hold_event(struct |
329 | + { |
330 | + ast_atomic_fetchadd_int((int *) &event->trunk_ref->trunk->hold_stations, 1); |
331 | + event->trunk_ref->state = SLA_TRUNK_STATE_ONHOLD_BYME; |
332 | +- ast_devstate_changed(AST_DEVICE_ONHOLD, "SLA:%s_%s", |
333 | +- event->station->name, event->trunk_ref->trunk->name); |
334 | ++ ast_devstate_changed(AST_DEVICE_ONHOLD, AST_DEVSTATE_CACHABLE, "SLA:%s_%s", |
335 | ++ event->station->name, event->trunk_ref->trunk->name); |
336 | + sla_change_trunk_state(event->trunk_ref->trunk, SLA_TRUNK_STATE_ONHOLD, |
337 | + INACTIVE_TRUNK_REFS, event->trunk_ref); |
338 | + |
339 | +@@ -6208,8 +6208,8 @@ static int sla_station_exec(struct ast_c |
340 | + sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_UP, ALL_TRUNK_REFS, NULL); |
341 | + else { |
342 | + trunk_ref->state = SLA_TRUNK_STATE_UP; |
343 | +- ast_devstate_changed(AST_DEVICE_INUSE, |
344 | +- "SLA:%s_%s", station->name, trunk_ref->trunk->name); |
345 | ++ ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, |
346 | ++ "SLA:%s_%s", station->name, trunk_ref->trunk->name); |
347 | + } |
348 | + } else if (trunk_ref->state == SLA_TRUNK_STATE_RINGING) { |
349 | + struct sla_ringing_trunk *ringing_trunk; |
350 | +--- a/channels/chan_agent.c |
351 | ++++ b/channels/chan_agent.c |
352 | +@@ -611,7 +611,7 @@ static struct ast_frame *agent_read(stru |
353 | + if (p->chan) { |
354 | + p->chan->_bridge = NULL; |
355 | + p->chan = NULL; |
356 | +- ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); |
357 | ++ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent); |
358 | + p->acknowledged = 0; |
359 | + } |
360 | + } else { |
361 | +@@ -866,7 +866,7 @@ static int agent_call(struct ast_channel |
362 | + } else { |
363 | + /* Agent hung-up */ |
364 | + p->chan = NULL; |
365 | +- ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); |
366 | ++ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent); |
367 | + } |
368 | + |
369 | + if (!res) { |
370 | +@@ -985,7 +985,7 @@ static int agent_hangup(struct ast_chann |
371 | + if (!p->loginstart) { |
372 | + p->logincallerid[0] = '\0'; |
373 | + } else { |
374 | +- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); |
375 | ++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent); |
376 | + } |
377 | + |
378 | + if (p->abouttograb) { |
379 | +@@ -2128,7 +2128,7 @@ static int login_exec(struct ast_channel |
380 | + } |
381 | + ast_mutex_unlock(&p->lock); |
382 | + AST_LIST_UNLOCK(&agents); |
383 | +- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); |
384 | ++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent); |
385 | + while (res >= 0) { |
386 | + ast_mutex_lock(&p->lock); |
387 | + if (p->deferlogoff && p->chan) { |
388 | +@@ -2149,7 +2149,7 @@ static int login_exec(struct ast_channel |
389 | + if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { |
390 | + ast_debug(1, "Wrapup time for %s expired!\n", p->agent); |
391 | + p->lastdisc = ast_tv(0, 0); |
392 | +- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); |
393 | ++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent); |
394 | + if (p->ackcall) { |
395 | + check_beep(p, 0); |
396 | + } else { |
397 | +@@ -2209,7 +2209,7 @@ static int login_exec(struct ast_channel |
398 | + ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); |
399 | + ast_verb(2, "Agent '%s' logged out\n", p->agent); |
400 | + /* If there is no owner, go ahead and kill it now */ |
401 | +- ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); |
402 | ++ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent); |
403 | + if (p->dead && !p->owner) { |
404 | + ast_mutex_destroy(&p->lock); |
405 | + ast_cond_destroy(&p->app_complete_cond); |
406 | +--- a/channels/chan_dahdi.c |
407 | ++++ b/channels/chan_dahdi.c |
408 | +@@ -3312,7 +3312,7 @@ static void dahdi_pri_update_span_devsta |
409 | + } |
410 | + if (pri->congestion_devstate != new_state) { |
411 | + pri->congestion_devstate = new_state; |
412 | +- ast_devstate_changed(AST_DEVICE_UNKNOWN, "DAHDI/I%d/congestion", pri->span); |
413 | ++ ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, "DAHDI/I%d/congestion", pri->span); |
414 | + } |
415 | + #if defined(THRESHOLD_DEVSTATE_PLACEHOLDER) |
416 | + /* Update the span threshold device state and report any change. */ |
417 | +@@ -3328,7 +3328,7 @@ static void dahdi_pri_update_span_devsta |
418 | + } |
419 | + if (pri->threshold_devstate != new_state) { |
420 | + pri->threshold_devstate = new_state; |
421 | +- ast_devstate_changed(AST_DEVICE_UNKNOWN, "DAHDI/I%d/threshold", pri->span); |
422 | ++ ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, "DAHDI/I%d/threshold", pri->span); |
423 | + } |
424 | + #endif /* defined(THRESHOLD_DEVSTATE_PLACEHOLDER) */ |
425 | + } |
426 | +@@ -9757,7 +9757,8 @@ static struct ast_channel *dahdi_new(str |
427 | + if (dashptr) { |
428 | + *dashptr = '\0'; |
429 | + } |
430 | +- ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, device_name); |
431 | ++ tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE; |
432 | ++ ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_NOT_CACHABLE, device_name); |
433 | + |
434 | + for (v = i->vars ; v ; v = v->next) |
435 | + pbx_builtin_setvar_helper(tmp, v->name, v->value); |
436 | +--- a/channels/chan_iax2.c |
437 | ++++ b/channels/chan_iax2.c |
438 | +@@ -5728,7 +5728,7 @@ static int iax2_getpeertrunk(struct sock |
439 | + } |
440 | + |
441 | + /*! \brief Create new call, interface with the PBX core */ |
442 | +-static struct ast_channel *ast_iax2_new(int callno, int state, format_t capability, const char *linkedid) |
443 | ++static struct ast_channel *ast_iax2_new(int callno, int state, format_t capability, const char *linkedid, unsigned int cachable) |
444 | + { |
445 | + struct ast_channel *tmp; |
446 | + struct chan_iax2_pvt *i; |
447 | +@@ -5797,6 +5797,10 @@ static struct ast_channel *ast_iax2_new( |
448 | + i->owner = tmp; |
449 | + i->capability = capability; |
450 | + |
451 | ++ if (!cachable) { |
452 | ++ tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE; |
453 | ++ } |
454 | ++ |
455 | + /* Set inherited variables */ |
456 | + if (i->vars) { |
457 | + for (v = i->vars ; v ; v = v->next) |
458 | +@@ -8085,7 +8089,7 @@ static int register_verify(int callno, s |
459 | + /* if challenge has been sent, but no challenge response if given, reject. */ |
460 | + goto return_unref; |
461 | + } |
462 | +- ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */ |
463 | ++ ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */ |
464 | + |
465 | + /* either Authentication has taken place, or a REGAUTH must be sent before verifying registration */ |
466 | + res = 0; |
467 | +@@ -8639,7 +8643,7 @@ static void __expire_registry(const void |
468 | + if (!ast_test_flag64(peer, IAX_TEMPONLY)) |
469 | + ast_db_del("IAX/Registry", peer->name); |
470 | + register_peer_exten(peer, 0); |
471 | +- ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */ |
472 | ++ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */ |
473 | + if (iax2_regfunk) |
474 | + iax2_regfunk(peer->name, 0); |
475 | + |
476 | +@@ -8693,7 +8697,7 @@ static void reg_source_db(struct iax2_pe |
477 | + } |
478 | + } |
479 | + |
480 | +- ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */ |
481 | ++ ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */ |
482 | + |
483 | + p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p)); |
484 | + if (p->expire == -1) { |
485 | +@@ -8770,14 +8774,14 @@ static int update_registry(struct sockad |
486 | + ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port)); |
487 | + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Registered\r\n", p->name); |
488 | + register_peer_exten(p, 1); |
489 | +- ast_devstate_changed(AST_DEVICE_UNKNOWN, "IAX2/%s", p->name); /* Activate notification */ |
490 | ++ ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */ |
491 | + } else if (!ast_test_flag64(p, IAX_TEMPONLY)) { |
492 | + ast_verb(3, "Unregistered IAX2 '%s' (%s)\n", p->name, |
493 | + ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED"); |
494 | + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unregistered\r\n", p->name); |
495 | + register_peer_exten(p, 0); |
496 | + ast_db_del("IAX/Registry", p->name); |
497 | +- ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", p->name); /* Activate notification */ |
498 | ++ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */ |
499 | + } |
500 | + /* Update the host */ |
501 | + /* Verify that the host is really there */ |
502 | +@@ -10278,7 +10282,8 @@ static int socket_process(struct iax2_th |
503 | + (f.frametype == AST_FRAME_IAX)) { |
504 | + if (ast_test_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART)) { |
505 | + ast_clear_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART); |
506 | +- if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL)) { |
507 | ++ if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL, |
508 | ++ ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED))) { |
509 | + ast_variables_destroy(ies.vars); |
510 | + ast_mutex_unlock(&iaxsl[fr->callno]); |
511 | + return 1; |
512 | +@@ -10911,13 +10916,13 @@ static int socket_process(struct iax2_th |
513 | + if (iaxs[fr->callno]->pingtime <= peer->maxms) { |
514 | + ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %d\n", peer->name, iaxs[fr->callno]->pingtime); |
515 | + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Reachable\r\nTime: %d\r\n", peer->name, iaxs[fr->callno]->pingtime); |
516 | +- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "IAX2/%s", peer->name); /* Activate notification */ |
517 | ++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */ |
518 | + } |
519 | + } else if ((peer->historicms > 0) && (peer->historicms <= peer->maxms)) { |
520 | + if (iaxs[fr->callno]->pingtime > peer->maxms) { |
521 | + ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%d ms)!\n", peer->name, iaxs[fr->callno]->pingtime); |
522 | + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Lagged\r\nTime: %d\r\n", peer->name, iaxs[fr->callno]->pingtime); |
523 | +- ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */ |
524 | ++ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */ |
525 | + } |
526 | + } |
527 | + peer->lastms = iaxs[fr->callno]->pingtime; |
528 | +@@ -11159,7 +11164,7 @@ static int socket_process(struct iax2_th |
529 | + using_prefs); |
530 | + |
531 | + ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED); |
532 | +- if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format, NULL))) |
533 | ++ if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format, NULL, 1))) |
534 | + iax2_destroy(fr->callno); |
535 | + else if (ies.vars) { |
536 | + struct ast_datastore *variablestore; |
537 | +@@ -11230,7 +11235,7 @@ immediatedial: |
538 | + ast_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat)); |
539 | + ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED); |
540 | + send_command(iaxs[fr->callno], AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, 0, NULL, 0, -1); |
541 | +- if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, NULL))) |
542 | ++ if (!(c = ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->peerformat, NULL, 1))) |
543 | + iax2_destroy(fr->callno); |
544 | + else if (ies.vars) { |
545 | + struct ast_datastore *variablestore; |
546 | +@@ -11982,7 +11987,7 @@ static void __iax2_poke_noanswer(const v |
547 | + if (peer->lastms > -1) { |
548 | + ast_log(LOG_NOTICE, "Peer '%s' is now UNREACHABLE! Time: %d\n", peer->name, peer->lastms); |
549 | + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: IAX2\r\nPeer: IAX2/%s\r\nPeerStatus: Unreachable\r\nTime: %d\r\n", peer->name, peer->lastms); |
550 | +- ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "IAX2/%s", peer->name); /* Activate notification */ |
551 | ++ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "IAX2/%s", peer->name); /* Activate notification */ |
552 | + } |
553 | + if ((callno = peer->callno) > 0) { |
554 | + ast_mutex_lock(&iaxsl[callno]); |
555 | +@@ -12150,7 +12155,7 @@ static struct ast_channel *iax2_request( |
556 | + if (cai.found) |
557 | + ast_string_field_set(iaxs[callno], host, pds.peer); |
558 | + |
559 | +- c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, requestor ? requestor->linkedid : NULL); |
560 | ++ c = ast_iax2_new(callno, AST_STATE_DOWN, cai.capability, requestor ? requestor->linkedid : NULL, cai.found); |
561 | + |
562 | + ast_mutex_unlock(&iaxsl[callno]); |
563 | + |
564 | +--- a/channels/chan_local.c |
565 | ++++ b/channels/chan_local.c |
566 | +@@ -1143,6 +1143,9 @@ static struct ast_channel *local_new(str |
567 | + tmp->tech_pvt = p; |
568 | + tmp2->tech_pvt = p; |
569 | + |
570 | ++ tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE; |
571 | ++ tmp2->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE; |
572 | ++ |
573 | + p->owner = tmp; |
574 | + p->chan = tmp2; |
575 | + p->u_owner = ast_module_user_add(p->owner); |
576 | +--- a/channels/chan_sip.c |
577 | ++++ b/channels/chan_sip.c |
578 | +@@ -6312,7 +6312,7 @@ static int update_call_counter(struct si |
579 | + } |
580 | + |
581 | + if (p) { |
582 | +- ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", p->name); |
583 | ++ ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", p->name); |
584 | + unref_peer(p, "update_call_counter: unref_peer from call counter"); |
585 | + } |
586 | + return 0; |
587 | +@@ -7510,6 +7510,9 @@ static struct ast_channel *sip_new(struc |
588 | + if (i->rtp) |
589 | + ast_jb_configure(tmp, &global_jbconf); |
590 | + |
591 | ++ if (!i->relatedpeer) { |
592 | ++ tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE; |
593 | ++ } |
594 | + /* Set channel variables for this call from configuration */ |
595 | + for (v = i->chanvars ; v ; v = v->next) { |
596 | + char valuebuf[1024]; |
597 | +@@ -14021,7 +14024,7 @@ static int expire_register(const void *d |
598 | + |
599 | + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: SIP\r\nPeer: SIP/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", peer->name); |
600 | + register_peer_exten(peer, FALSE); /* Remove regexten */ |
601 | +- ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name); |
602 | ++ ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name); |
603 | + |
604 | + /* Do we need to release this peer from memory? |
605 | + Only for realtime peers and autocreated peers |
606 | +@@ -14803,8 +14806,9 @@ static void sip_peer_hold(struct sip_pvt |
607 | + ast_atomic_fetchadd_int(&p->relatedpeer->onHold, (hold ? +1 : -1)); |
608 | + |
609 | + /* Request device state update */ |
610 | +- ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", p->relatedpeer->name); |
611 | +- |
612 | ++ ast_devstate_changed(AST_DEVICE_UNKNOWN, (p->owner->flags & AST_FLAG_DISABLE_DEVSTATE_CACHE ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), |
613 | ++ "SIP/%s", p->relatedpeer->name); |
614 | ++ |
615 | + return; |
616 | + } |
617 | + |
618 | +@@ -15208,7 +15212,7 @@ static enum check_auth_result register_v |
619 | + } |
620 | + } |
621 | + if (!res) { |
622 | +- ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name); |
623 | ++ ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name); |
624 | + } |
625 | + if (res < 0) { |
626 | + switch (res) { |
627 | +@@ -21122,7 +21126,7 @@ static void handle_response_peerpoke(str |
628 | + |
629 | + ast_log(LOG_NOTICE, "Peer '%s' is now %s. (%dms / %dms)\n", |
630 | + peer->name, s, pingtime, peer->maxms); |
631 | +- ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name); |
632 | ++ ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name); |
633 | + if (sip_cfg.peer_rtupdate) { |
634 | + ast_update_realtime(ast_check_realtime("sipregs") ? "sipregs" : "sippeers", "name", peer->name, "lastms", str_lastms, SENTINEL); |
635 | + } |
636 | +@@ -26540,7 +26544,7 @@ static int sip_poke_noanswer(const void |
637 | + /* Don't send a devstate change if nothing changed. */ |
638 | + if (peer->lastms > -1) { |
639 | + peer->lastms = -1; |
640 | +- ast_devstate_changed(AST_DEVICE_UNKNOWN, "SIP/%s", peer->name); |
641 | ++ ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "SIP/%s", peer->name); |
642 | + } |
643 | + |
644 | + /* Try again quickly */ |
645 | +--- a/channels/chan_skinny.c |
646 | ++++ b/channels/chan_skinny.c |
647 | +@@ -1925,7 +1925,7 @@ static int skinny_register(struct skinny |
648 | + register_exten(l); |
649 | + /* initialize MWI on line and device */ |
650 | + mwi_event_cb(0, l); |
651 | +- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name); |
652 | ++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name); |
653 | + } |
654 | + --instance; |
655 | + } |
656 | +@@ -1963,7 +1963,7 @@ static int skinny_unregister(struct skin |
657 | + l->instance = 0; |
658 | + manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Unregistered\r\n", l->name, d->name); |
659 | + unregister_exten(l); |
660 | +- ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Skinny/%s@%s", l->name, d->name); |
661 | ++ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name); |
662 | + } |
663 | + } |
664 | + } |
665 | +@@ -5321,7 +5321,7 @@ static int handle_stimulus_message(struc |
666 | + ast_verb(1, "RECEIVED UNKNOWN STIMULUS: %d(%d/%d)\n", event, instance, callreference); |
667 | + break; |
668 | + } |
669 | +- ast_devstate_changed(AST_DEVICE_UNKNOWN, "Skinny/%s@%s", l->name, d->name); |
670 | ++ ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name); |
671 | + |
672 | + return 1; |
673 | + } |
674 | +@@ -5372,7 +5372,7 @@ static int handle_offhook_message(struct |
675 | + transmit_ringer_mode(d, SKINNY_RING_OFF); |
676 | + l->hookstate = SKINNY_OFFHOOK; |
677 | + |
678 | +- ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s@%s", l->name, d->name); |
679 | ++ ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name); |
680 | + |
681 | + if (sub && sub->onhold) { |
682 | + return 1; |
683 | +@@ -5448,7 +5448,7 @@ static int handle_onhook_message(struct |
684 | + return 0; |
685 | + } |
686 | + |
687 | +- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name); |
688 | ++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name); |
689 | + |
690 | + if (sub->onhold) { |
691 | + return 0; |
692 | +@@ -5834,7 +5834,7 @@ static int handle_soft_key_event_message |
693 | + return 0; |
694 | + } |
695 | + |
696 | +- ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s@%s", l->name, d->name); |
697 | ++ ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name); |
698 | + |
699 | + switch(event) { |
700 | + case SOFTKEY_NONE: |
701 | +@@ -6049,7 +6049,7 @@ static int handle_soft_key_event_message |
702 | + transmit_callstate(d, l->instance, sub->callid, l->hookstate); |
703 | + } |
704 | + |
705 | +- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name); |
706 | ++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name); |
707 | + if (skinnydebug) |
708 | + ast_verb(1, "Skinny %s@%s went on hook\n", l->name, d->name); |
709 | + if (l->transfer && sub->xferor && sub->owner->_state >= AST_STATE_RING) { |
710 | +@@ -6073,7 +6073,7 @@ static int handle_soft_key_event_message |
711 | + } |
712 | + } |
713 | + if ((l->hookstate == SKINNY_ONHOOK) && (AST_LIST_NEXT(sub, list) && !AST_LIST_NEXT(sub, list)->rtp)) { |
714 | +- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name); |
715 | ++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Skinny/%s@%s", l->name, d->name); |
716 | + } |
717 | + } |
718 | + break; |
719 | +--- a/funcs/func_devstate.c |
720 | ++++ b/funcs/func_devstate.c |
721 | +@@ -132,7 +132,7 @@ static int devstate_write(struct ast_cha |
722 | + |
723 | + ast_db_put(astdb_family, data, value); |
724 | + |
725 | +- ast_devstate_changed(state_val, "Custom:%s", data); |
726 | ++ ast_devstate_changed(state_val, AST_DEVSTATE_CACHABLE, "Custom:%s", data); |
727 | + |
728 | + return 0; |
729 | + } |
730 | +@@ -294,7 +294,7 @@ static char *handle_cli_devstate_change( |
731 | + |
732 | + ast_db_put(astdb_family, dev, state); |
733 | + |
734 | +- ast_devstate_changed(state_val, "Custom:%s", dev); |
735 | ++ ast_devstate_changed(state_val, AST_DEVSTATE_CACHABLE, "Custom:%s", dev); |
736 | + |
737 | + return CLI_SUCCESS; |
738 | + } |
739 | +@@ -340,7 +340,7 @@ static int load_module(void) |
740 | + if (dev_name <= (const char *) 1) |
741 | + continue; |
742 | + ast_devstate_changed(ast_devstate_val(db_entry->data), |
743 | +- "Custom:%s\n", dev_name); |
744 | ++ AST_DEVSTATE_CACHABLE, "Custom:%s\n", dev_name); |
745 | + } |
746 | + ast_db_freetree(db_tree); |
747 | + db_tree = NULL; |
748 | +--- a/include/asterisk/channel.h |
749 | ++++ b/include/asterisk/channel.h |
750 | +@@ -936,6 +936,12 @@ enum { |
751 | + * some non-traditional dialplans (like AGI) to continue to function. |
752 | + */ |
753 | + AST_FLAG_DISABLE_WORKAROUNDS = (1 << 20), |
754 | ++ /*! Disable device state event caching. This allows allows channel |
755 | ++ * drivers to selectively prevent device state events from being cached |
756 | ++ * by certain channels such as anonymous calls which have no persistent |
757 | ++ * represenatation that can be tracked. |
758 | ++ */ |
759 | ++ AST_FLAG_DISABLE_DEVSTATE_CACHE = (1 << 21), |
760 | + }; |
761 | + |
762 | + /*! \brief ast_bridge_config flags */ |
763 | +--- a/include/asterisk/devicestate.h |
764 | ++++ b/include/asterisk/devicestate.h |
765 | +@@ -61,6 +61,14 @@ enum ast_device_state { |
766 | + AST_DEVICE_TOTAL, /*/ Total num of device states, used for testing */ |
767 | + }; |
768 | + |
769 | ++/*! \brief Device State Cachability |
770 | ++ * \note This is used to define the cachability of a device state when set. |
771 | ++ */ |
772 | ++enum ast_devstate_cache { |
773 | ++ AST_DEVSTATE_NOT_CACHABLE, /*!< This device state is not cachable */ |
774 | ++ AST_DEVSTATE_CACHABLE, /*!< This device state is cachable */ |
775 | ++}; |
776 | ++ |
777 | + /*! \brief Devicestate provider call back */ |
778 | + typedef enum ast_device_state (*ast_devstate_prov_cb_type)(const char *data); |
779 | + |
780 | +@@ -129,6 +137,7 @@ enum ast_device_state ast_device_state(c |
781 | + * \brief Tells Asterisk the State for Device is changed |
782 | + * |
783 | + * \param state the new state of the device |
784 | ++ * \param cachable whether this device state is cachable |
785 | + * \param fmt device name like a dial string with format parameters |
786 | + * |
787 | + * The new state of the device will be sent off to any subscribers |
788 | +@@ -138,13 +147,14 @@ enum ast_device_state ast_device_state(c |
789 | + * \retval 0 on success |
790 | + * \retval -1 on failure |
791 | + */ |
792 | +-int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...) |
793 | +- __attribute__((format(printf, 2, 3))); |
794 | ++int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt, ...) |
795 | ++ __attribute__((format(printf, 3, 4))); |
796 | + |
797 | + /*! |
798 | + * \brief Tells Asterisk the State for Device is changed |
799 | + * |
800 | + * \param state the new state of the device |
801 | ++ * \param cachable whether this device state is cachable |
802 | + * \param device device name like a dial string with format parameters |
803 | + * |
804 | + * The new state of the device will be sent off to any subscribers |
805 | +@@ -154,7 +164,7 @@ int ast_devstate_changed(enum ast_device |
806 | + * \retval 0 on success |
807 | + * \retval -1 on failure |
808 | + */ |
809 | +-int ast_devstate_changed_literal(enum ast_device_state state, const char *device); |
810 | ++int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device); |
811 | + |
812 | + /*! |
813 | + * \brief Tells Asterisk the State for Device is changed. |
814 | +--- a/include/asterisk/event_defs.h |
815 | ++++ b/include/asterisk/event_defs.h |
816 | +@@ -283,8 +283,14 @@ enum ast_event_ie_type { |
817 | + AST_EVENT_IE_CHALLENGE = 0x0032, |
818 | + AST_EVENT_IE_RESPONSE = 0x0033, |
819 | + AST_EVENT_IE_EXPECTED_RESPONSE = 0x0034, |
820 | ++ /*! |
821 | ++ * \brief Event non-cachability flag |
822 | ++ * Used by: All events |
823 | ++ * Payload type: UINT |
824 | ++ */ |
825 | ++ AST_EVENT_IE_CACHABLE = 0x0035, |
826 | + /*! \brief Must be the last IE value +1 */ |
827 | +- AST_EVENT_IE_TOTAL = 0x0035, |
828 | ++ AST_EVENT_IE_TOTAL = 0x0036, |
829 | + }; |
830 | + |
831 | + /*! |
832 | +--- a/main/channel.c |
833 | ++++ b/main/channel.c |
834 | +@@ -285,6 +285,7 @@ static void channel_data_add_flags(struc |
835 | + ast_data_add_bool(tree, "BRIDGE_HANGUP_RUN", ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN)); |
836 | + ast_data_add_bool(tree, "BRIDGE_HANGUP_DONT", ast_test_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT)); |
837 | + ast_data_add_bool(tree, "DISABLE_WORKAROUNDS", ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS)); |
838 | ++ ast_data_add_bool(tree, "DISABLE_DEVSTATE_CACHE", ast_test_flag(chan, AST_FLAG_DISABLE_DEVSTATE_CACHE)); |
839 | + } |
840 | + |
841 | + #if defined(KEEP_TILL_CHANNEL_PARTY_NUMBER_INFO_NEEDED) |
842 | +@@ -2477,7 +2478,7 @@ static void ast_channel_destructor(void |
843 | + * instance is dead, we don't know the state of all other possible |
844 | + * instances. |
845 | + */ |
846 | +- ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, device_name); |
847 | ++ ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (chan->flags & AST_FLAG_DISABLE_DEVSTATE_CACHE ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), device_name); |
848 | + } |
849 | + } |
850 | + |
851 | +@@ -6918,7 +6919,7 @@ int ast_setstate(struct ast_channel *cha |
852 | + /* We have to pass AST_DEVICE_UNKNOWN here because it is entirely possible that the channel driver |
853 | + * for this channel is using the callback method for device state. If we pass in an actual state here |
854 | + * we override what they are saying the state is and things go amuck. */ |
855 | +- ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, name); |
856 | ++ ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, (chan->flags & AST_FLAG_DISABLE_DEVSTATE_CACHE ? AST_DEVSTATE_NOT_CACHABLE : AST_DEVSTATE_CACHABLE), name); |
857 | + |
858 | + /* setstate used to conditionally report Newchannel; this is no more */ |
859 | + ast_manager_event(chan, EVENT_FLAG_CALL, "Newstate", |
860 | +--- a/main/devicestate.c |
861 | ++++ b/main/devicestate.c |
862 | +@@ -170,6 +170,7 @@ static AST_RWLIST_HEAD_STATIC(devstate_p |
863 | + |
864 | + struct state_change { |
865 | + AST_LIST_ENTRY(state_change) list; |
866 | ++ enum ast_devstate_cache cachable; |
867 | + char device[1]; |
868 | + }; |
869 | + |
870 | +@@ -187,6 +188,7 @@ struct devstate_change { |
871 | + AST_LIST_ENTRY(devstate_change) entry; |
872 | + uint32_t state; |
873 | + struct ast_eid eid; |
874 | ++ enum ast_devstate_cache cachable; |
875 | + char device[1]; |
876 | + }; |
877 | + |
878 | +@@ -422,7 +424,7 @@ static int getproviderstate(const char * |
879 | + return res; |
880 | + } |
881 | + |
882 | +-static void devstate_event(const char *device, enum ast_device_state state) |
883 | ++static void devstate_event(const char *device, enum ast_device_state state, int cachable) |
884 | + { |
885 | + struct ast_event *event; |
886 | + enum ast_event_type event_type; |
887 | +@@ -438,18 +440,23 @@ static void devstate_event(const char *d |
888 | + ast_debug(3, "device '%s' state '%d'\n", device, state); |
889 | + |
890 | + if (!(event = ast_event_new(event_type, |
891 | +- AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device, |
892 | +- AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state, |
893 | +- AST_EVENT_IE_END))) { |
894 | ++ AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, device, |
895 | ++ AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, state, |
896 | ++ AST_EVENT_IE_CACHABLE, AST_EVENT_IE_PLTYPE_UINT, cachable, |
897 | ++ AST_EVENT_IE_END))) { |
898 | + return; |
899 | + } |
900 | + |
901 | +- ast_event_queue_and_cache(event); |
902 | ++ if (cachable) { |
903 | ++ ast_event_queue_and_cache(event); |
904 | ++ } else { |
905 | ++ ast_event_queue(event); |
906 | ++ } |
907 | + } |
908 | + |
909 | + /*! Called by the state change thread to find out what the state is, and then |
910 | + * to queue up the state change event */ |
911 | +-static void do_state_change(const char *device) |
912 | ++static void do_state_change(const char *device, int cachable) |
913 | + { |
914 | + enum ast_device_state state; |
915 | + |
916 | +@@ -457,10 +464,10 @@ static void do_state_change(const char * |
917 | + |
918 | + ast_debug(3, "Changing state for %s - state %d (%s)\n", device, state, ast_devstate2str(state)); |
919 | + |
920 | +- devstate_event(device, state); |
921 | ++ devstate_event(device, state, cachable); |
922 | + } |
923 | + |
924 | +-int ast_devstate_changed_literal(enum ast_device_state state, const char *device) |
925 | ++int ast_devstate_changed_literal(enum ast_device_state state, enum ast_devstate_cache cachable, const char *device) |
926 | + { |
927 | + struct state_change *change; |
928 | + |
929 | +@@ -481,14 +488,15 @@ int ast_devstate_changed_literal(enum as |
930 | + */ |
931 | + |
932 | + if (state != AST_DEVICE_UNKNOWN) { |
933 | +- devstate_event(device, state); |
934 | ++ devstate_event(device, state, cachable); |
935 | + } else if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) { |
936 | + /* we could not allocate a change struct, or */ |
937 | + /* there is no background thread, so process the change now */ |
938 | +- do_state_change(device); |
939 | ++ do_state_change(device, cachable); |
940 | + } else { |
941 | + /* queue the change */ |
942 | + strcpy(change->device, device); |
943 | ++ change->cachable = cachable; |
944 | + AST_LIST_LOCK(&state_changes); |
945 | + AST_LIST_INSERT_TAIL(&state_changes, change, list); |
946 | + ast_cond_signal(&change_pending); |
947 | +@@ -500,10 +508,10 @@ int ast_devstate_changed_literal(enum as |
948 | + |
949 | + int ast_device_state_changed_literal(const char *dev) |
950 | + { |
951 | +- return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, dev); |
952 | ++ return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, dev); |
953 | + } |
954 | + |
955 | +-int ast_devstate_changed(enum ast_device_state state, const char *fmt, ...) |
956 | ++int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt, ...) |
957 | + { |
958 | + char buf[AST_MAX_EXTENSION]; |
959 | + va_list ap; |
960 | +@@ -512,7 +520,7 @@ int ast_devstate_changed(enum ast_device |
961 | + vsnprintf(buf, sizeof(buf), fmt, ap); |
962 | + va_end(ap); |
963 | + |
964 | +- return ast_devstate_changed_literal(state, buf); |
965 | ++ return ast_devstate_changed_literal(state, cachable, buf); |
966 | + } |
967 | + |
968 | + int ast_device_state_changed(const char *fmt, ...) |
969 | +@@ -524,7 +532,7 @@ int ast_device_state_changed(const char |
970 | + vsnprintf(buf, sizeof(buf), fmt, ap); |
971 | + va_end(ap); |
972 | + |
973 | +- return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, buf); |
974 | ++ return ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, buf); |
975 | + } |
976 | + |
977 | + /*! \brief Go through the dev state change queue and update changes in the dev state thread */ |
978 | +@@ -544,7 +552,7 @@ static void *do_devstate_changes(void *d |
979 | + /* Process each state change */ |
980 | + while ((current = next)) { |
981 | + next = AST_LIST_NEXT(current, list); |
982 | +- do_state_change(current->device); |
983 | ++ do_state_change(current->device, current->cachable); |
984 | + ast_free(current); |
985 | + } |
986 | + } |
987 | +@@ -588,7 +596,7 @@ static void devstate_cache_cb(const stru |
988 | + collection->num_states++; |
989 | + } |
990 | + |
991 | +-static void process_collection(const char *device, struct change_collection *collection) |
992 | ++static void process_collection(const char *device, enum ast_devstate_cache cachable, struct change_collection *collection) |
993 | + { |
994 | + int i; |
995 | + struct ast_devstate_aggregate agg; |
996 | +@@ -639,7 +647,11 @@ static void process_collection(const cha |
997 | + return; |
998 | + } |
999 | + |
1000 | +- ast_event_queue_and_cache(event); |
1001 | ++ if (cachable) { |
1002 | ++ ast_event_queue_and_cache(event); |
1003 | ++ } else { |
1004 | ++ ast_event_queue(event); |
1005 | ++ } |
1006 | + } |
1007 | + |
1008 | + static void handle_devstate_change(struct devstate_change *sc) |
1009 | +@@ -665,7 +677,7 @@ static void handle_devstate_change(struc |
1010 | + /* Populate the collection of device states from the cache */ |
1011 | + ast_event_dump_cache(tmp_sub); |
1012 | + |
1013 | +- process_collection(sc->device, &collection); |
1014 | ++ process_collection(sc->device, sc->cachable, &collection); |
1015 | + |
1016 | + ast_event_sub_destroy(tmp_sub); |
1017 | + } |
1018 | +@@ -694,10 +706,12 @@ static void devstate_change_collector_cb |
1019 | + const char *device; |
1020 | + const struct ast_eid *eid; |
1021 | + uint32_t state; |
1022 | ++ enum ast_devstate_cache cachable = AST_DEVSTATE_CACHABLE; |
1023 | + |
1024 | + device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE); |
1025 | + eid = ast_event_get_ie_raw(event, AST_EVENT_IE_EID); |
1026 | + state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE); |
1027 | ++ cachable = ast_event_get_ie_uint(event, AST_EVENT_IE_CACHABLE); |
1028 | + |
1029 | + if (ast_strlen_zero(device) || !eid) { |
1030 | + ast_log(LOG_ERROR, "Invalid device state change event received\n"); |
1031 | +@@ -710,6 +724,7 @@ static void devstate_change_collector_cb |
1032 | + strcpy(sc->device, device); |
1033 | + sc->eid = *eid; |
1034 | + sc->state = state; |
1035 | ++ sc->cachable = cachable; |
1036 | + |
1037 | + ast_mutex_lock(&devstate_collector.lock); |
1038 | + AST_LIST_INSERT_TAIL(&devstate_collector.devstate_change_q, sc, entry); |
1039 | +--- a/main/event.c |
1040 | ++++ b/main/event.c |
1041 | +@@ -264,6 +264,7 @@ static const struct ie_map { |
1042 | + [AST_EVENT_IE_CHALLENGE] = { AST_EVENT_IE_PLTYPE_STR, "Challenge" }, |
1043 | + [AST_EVENT_IE_RESPONSE] = { AST_EVENT_IE_PLTYPE_STR, "Response" }, |
1044 | + [AST_EVENT_IE_EXPECTED_RESPONSE] = { AST_EVENT_IE_PLTYPE_STR, "ExpectedResponse" }, |
1045 | ++ [AST_EVENT_IE_CACHABLE] = { AST_EVENT_IE_PLTYPE_UINT, "Cachable" }, |
1046 | + }; |
1047 | + |
1048 | + const char *ast_event_get_type_name(const struct ast_event *event) |
1049 | +--- a/main/features.c |
1050 | ++++ b/main/features.c |
1051 | +@@ -1061,7 +1061,7 @@ static void notify_metermaids(const char |
1052 | + ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", |
1053 | + exten, context, ast_devstate2str(state)); |
1054 | + |
1055 | +- ast_devstate_changed(state, "park:%s@%s", exten, context); |
1056 | ++ ast_devstate_changed(state, AST_DEVSTATE_CACHABLE, "park:%s@%s", exten, context); |
1057 | + } |
1058 | + |
1059 | + /*! \brief metermaids callback from devicestate.c */ |
1060 | +--- a/res/res_calendar.c |
1061 | ++++ b/res/res_calendar.c |
1062 | +@@ -571,9 +571,9 @@ static struct ast_calendar_event *destro |
1063 | + * but haven't hit the end event yet, go ahead and set the devicestate to the current busy status */ |
1064 | + if (event->bs_start_sched < 0 && event->bs_end_sched >= 0) { |
1065 | + if (!calendar_is_busy(event->owner)) { |
1066 | +- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar:%s", event->owner->name); |
1067 | ++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name); |
1068 | + } else { |
1069 | +- ast_devstate_changed(AST_DEVICE_BUSY, "Calendar:%s", event->owner->name); |
1070 | ++ ast_devstate_changed(AST_DEVICE_BUSY, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name); |
1071 | + } |
1072 | + } |
1073 | + |
1074 | +@@ -814,9 +814,9 @@ static int calendar_devstate_change(cons |
1075 | + /* We can have overlapping events, so ignore the event->busy_state and check busy state |
1076 | + * based on all events in the calendar */ |
1077 | + if (!calendar_is_busy(event->owner)) { |
1078 | +- ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Calendar:%s", event->owner->name); |
1079 | ++ ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name); |
1080 | + } else { |
1081 | +- ast_devstate_changed(AST_DEVICE_BUSY, "Calendar:%s", event->owner->name); |
1082 | ++ ast_devstate_changed(AST_DEVICE_BUSY, AST_DEVSTATE_CACHABLE, "Calendar:%s", event->owner->name); |
1083 | + } |
1084 | + |
1085 | + event = ast_calendar_unref_event(event); |
1086 | +--- a/res/res_jabber.c |
1087 | ++++ b/res/res_jabber.c |
1088 | +@@ -350,7 +350,7 @@ static char *aji_cli_create_leafnode(str |
1089 | + static void aji_create_affiliations(struct aji_client *client, const char *node); |
1090 | + static iks* aji_pubsub_iq_create(struct aji_client *client, const char *type); |
1091 | + static void aji_publish_device_state(struct aji_client *client, const char * device, |
1092 | +- const char *device_state); |
1093 | ++ const char *device_state, unsigned int cachable); |
1094 | + static int aji_handle_pubsub_error(void *data, ikspak *pak); |
1095 | + static int aji_handle_pubsub_event(void *data, ikspak *pak); |
1096 | + static void aji_pubsub_subscribe(struct aji_client *client, const char *node); |
1097 | +@@ -364,7 +364,7 @@ static void aji_publish_mwi(struct aji_c |
1098 | + static void aji_devstate_cb(const struct ast_event *ast_event, void *data); |
1099 | + static void aji_mwi_cb(const struct ast_event *ast_event, void *data); |
1100 | + static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node, |
1101 | +- const char *event_type); |
1102 | ++ const char *event_type, unsigned int cachable); |
1103 | + /* No transports in this version */ |
1104 | + /* |
1105 | + static int aji_create_transport(char *label, struct aji_client *client); |
1106 | +@@ -3198,6 +3198,7 @@ static void aji_devstate_cb(const struct |
1107 | + { |
1108 | + const char *device; |
1109 | + const char *device_state; |
1110 | ++ unsigned int cachable; |
1111 | + struct aji_client *client; |
1112 | + if (ast_eid_cmp(&ast_eid_default, ast_event_get_ie_raw(ast_event, AST_EVENT_IE_EID))) |
1113 | + { |
1114 | +@@ -3209,7 +3210,8 @@ static void aji_devstate_cb(const struct |
1115 | + client = ASTOBJ_REF((struct aji_client *) data); |
1116 | + device = ast_event_get_ie_str(ast_event, AST_EVENT_IE_DEVICE); |
1117 | + device_state = ast_devstate_str(ast_event_get_ie_uint(ast_event, AST_EVENT_IE_STATE)); |
1118 | +- aji_publish_device_state(client, device, device_state); |
1119 | ++ cachable = ast_event_get_ie_uint(ast_event, AST_EVENT_IE_CACHABLE); |
1120 | ++ aji_publish_device_state(client, device, device_state, cachable); |
1121 | + ASTOBJ_UNREF(client, ast_aji_client_destroy); |
1122 | + } |
1123 | + |
1124 | +@@ -3249,11 +3251,13 @@ static void aji_init_event_distribution( |
1125 | + */ |
1126 | + static int aji_handle_pubsub_event(void *data, ikspak *pak) |
1127 | + { |
1128 | +- char *item_id, *device_state, *context; |
1129 | ++ char *item_id, *device_state, *context, *cachable_str; |
1130 | + int oldmsgs, newmsgs; |
1131 | + iks *item, *item_content; |
1132 | + struct ast_eid pubsub_eid; |
1133 | + struct ast_event *event; |
1134 | ++ unsigned int cachable = AST_DEVSTATE_CACHABLE; |
1135 | ++ |
1136 | + item = iks_find(iks_find(iks_find(pak->x, "event"), "items"), "item"); |
1137 | + if (!item) { |
1138 | + ast_log(LOG_ERROR, "Could not parse incoming PubSub event\n"); |
1139 | +@@ -3268,11 +3272,14 @@ static int aji_handle_pubsub_event(void |
1140 | + } |
1141 | + if (!strcasecmp(iks_name(item_content), "state")) { |
1142 | + device_state = iks_find_cdata(item, "state"); |
1143 | ++ if ((cachable_str = iks_find_cdata(item, "cachable"))) { |
1144 | ++ sscanf(cachable_str, "%30d", &cachable); |
1145 | ++ } |
1146 | + if (!(event = ast_event_new(AST_EVENT_DEVICE_STATE_CHANGE, |
1147 | +- AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE, |
1148 | +- AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID, |
1149 | +- AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid), |
1150 | +- AST_EVENT_IE_END))) { |
1151 | ++ AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, item_id, AST_EVENT_IE_STATE, |
1152 | ++ AST_EVENT_IE_PLTYPE_UINT, ast_devstate_val(device_state), AST_EVENT_IE_EID, |
1153 | ++ AST_EVENT_IE_PLTYPE_RAW, &pubsub_eid, sizeof(pubsub_eid), |
1154 | ++ AST_EVENT_IE_END))) { |
1155 | + return IKS_FILTER_EAT; |
1156 | + } |
1157 | + } else if (!strcasecmp(iks_name(item_content), "mailbox")) { |
1158 | +@@ -3292,7 +3299,13 @@ static int aji_handle_pubsub_event(void |
1159 | + iks_name(item_content)); |
1160 | + return IKS_FILTER_EAT; |
1161 | + } |
1162 | +- ast_event_queue_and_cache(event); |
1163 | ++ |
1164 | ++ if (cachable == AST_DEVSTATE_CACHABLE) { |
1165 | ++ ast_event_queue_and_cache(event); |
1166 | ++ } else { |
1167 | ++ ast_event_queue(event); |
1168 | ++ } |
1169 | ++ |
1170 | + return IKS_FILTER_EAT; |
1171 | + } |
1172 | + |
1173 | +@@ -3367,7 +3380,7 @@ static void aji_pubsub_subscribe(struct |
1174 | + * \return iks * |
1175 | + */ |
1176 | + static iks* aji_build_publish_skeleton(struct aji_client *client, const char *node, |
1177 | +- const char *event_type) |
1178 | ++ const char *event_type, unsigned int cachable) |
1179 | + { |
1180 | + iks *request = aji_pubsub_iq_create(client, "set"); |
1181 | + iks *pubsub, *publish, *item; |
1182 | +@@ -3381,8 +3394,24 @@ static iks* aji_build_publish_skeleton(s |
1183 | + } |
1184 | + item = iks_insert(publish, "item"); |
1185 | + iks_insert_attrib(item, "id", node); |
1186 | +- return item; |
1187 | + |
1188 | ++ if (cachable == AST_DEVSTATE_NOT_CACHABLE) { |
1189 | ++ iks *options, *x, *field_form_type, *field_persist; |
1190 | ++ |
1191 | ++ options = iks_insert(pubsub, "publish-options"); |
1192 | ++ x = iks_insert(options, "x"); |
1193 | ++ iks_insert_attrib(x, "xmlns", "jabber:x:data"); |
1194 | ++ iks_insert_attrib(x, "type", "submit"); |
1195 | ++ field_form_type = iks_insert(x, "field"); |
1196 | ++ iks_insert_attrib(field_form_type, "var", "FORM_TYPE"); |
1197 | ++ iks_insert_attrib(field_form_type, "type", "hidden"); |
1198 | ++ iks_insert_cdata(iks_insert(field_form_type, "value"), "http://jabber.org/protocol/pubsub#publish-options", 0); |
1199 | ++ field_persist = iks_insert(x, "field"); |
1200 | ++ iks_insert_attrib(field_persist, "var", "pubsub#persist_items"); |
1201 | ++ iks_insert_cdata(iks_insert(field_persist, "value"), "0", 1); |
1202 | ++ } |
1203 | ++ |
1204 | ++ return item; |
1205 | + } |
1206 | + |
1207 | + /*! |
1208 | +@@ -3393,11 +3422,11 @@ static iks* aji_build_publish_skeleton(s |
1209 | + * \return void |
1210 | + */ |
1211 | + static void aji_publish_device_state(struct aji_client *client, const char *device, |
1212 | +- const char *device_state) |
1213 | ++ const char *device_state, unsigned int cachable) |
1214 | + { |
1215 | +- iks *request = aji_build_publish_skeleton(client, device, "device_state"); |
1216 | ++ iks *request = aji_build_publish_skeleton(client, device, "device_state", cachable); |
1217 | + iks *state; |
1218 | +- char eid_str[20]; |
1219 | ++ char eid_str[20], cachable_str[2]; |
1220 | + if (ast_test_flag(&pubsubflags, AJI_PUBSUB_AUTOCREATE)) { |
1221 | + if (ast_test_flag(&pubsubflags, AJI_XEP0248)) { |
1222 | + aji_create_pubsub_node(client, "leaf", device, "device_state"); |
1223 | +@@ -3409,6 +3438,8 @@ static void aji_publish_device_state(str |
1224 | + state = iks_insert(request, "state"); |
1225 | + iks_insert_attrib(state, "xmlns", "http://asterisk.org"); |
1226 | + iks_insert_attrib(state, "eid", eid_str); |
1227 | ++ snprintf(cachable_str, sizeof(cachable_str), "%u", cachable); |
1228 | ++ iks_insert_attrib(state, "cachable", cachable_str); |
1229 | + iks_insert_cdata(state, device_state, strlen(device_state)); |
1230 | + ast_aji_send(client, iks_root(request)); |
1231 | + iks_delete(request); |
1232 | +@@ -3428,7 +3459,7 @@ static void aji_publish_mwi(struct aji_c |
1233 | + char eid_str[20]; |
1234 | + iks *mailbox_node, *request; |
1235 | + snprintf(full_mailbox, sizeof(full_mailbox), "%s@%s", mailbox, context); |
1236 | +- request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting"); |
1237 | ++ request = aji_build_publish_skeleton(client, full_mailbox, "message_waiting", 1); |
1238 | + ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default); |
1239 | + mailbox_node = iks_insert(request, "mailbox"); |
1240 | + iks_insert_attrib(mailbox_node, "xmlns", "http://asterisk.org"); |
1241 | |
1242 | === added file 'debian/patches/AST-2013-002' |
1243 | --- debian/patches/AST-2013-002 1970-01-01 00:00:00 +0000 |
1244 | +++ debian/patches/AST-2013-002 2013-07-28 21:58:23 +0000 |
1245 | @@ -0,0 +1,55 @@ |
1246 | +From: Matthew Jordan <mjordan@digium.com> |
1247 | +Date: Wed, 27 Mar 2013 14:35:11 +0000 |
1248 | +Subject: AST-2013-002: Prevent denial of service in HTTP server |
1249 | +Origin: http://svnview.digium.com/svn/asterisk?view=rev&rev=383976 |
1250 | +Bug: https://issues.asterisk.org/jira/browse/ASTERISK-20967 |
1251 | +CVE: CVE-2013-2686 |
1252 | + |
1253 | +AST-2012-014, fixed in January of this year, contained a fix for Asterisk's |
1254 | +HTTP server for a remotely-triggered crash. While the fix put in place fixed |
1255 | +the possibility for the crash to be triggered, a denial of service vector still |
1256 | +exists with that solution if an attacker sends one or more HTTP POST requests |
1257 | +with very large Content-Length values. This patch resolves this by capping |
1258 | +the Content-Length at 1024 bytes. Any attempt to send an HTTP POST with |
1259 | +Content-Length greater than this cap will not result in any memory allocation. |
1260 | +The POST will be responded to with an HTTP 413 "Request Entity Too Large" |
1261 | +response. |
1262 | + |
1263 | +This issue was reported by Christoph Hebeisen of TELUS Security Labs |
1264 | + |
1265 | +See Also: http://downloads.asterisk.org/pub/security/AST-2013-002.html |
1266 | + |
1267 | +--- |
1268 | + main/http.c | 9 +++++++++ |
1269 | + 1 file changed, 9 insertions(+) |
1270 | + |
1271 | +diff --git a/main/http.c b/main/http.c |
1272 | +index 1b5f2b6..4b73acb 100644 |
1273 | +--- a/main/http.c |
1274 | ++++ b/main/http.c |
1275 | +@@ -612,6 +612,8 @@ static void http_decode(char *s) |
1276 | + ast_uri_decode(s); |
1277 | + } |
1278 | + |
1279 | ++#define MAX_POST_CONTENT 1025 |
1280 | ++ |
1281 | + /* |
1282 | + * get post variables from client Request Entity-Body, if content type is |
1283 | + * application/x-www-form-urlencoded |
1284 | +@@ -644,6 +646,13 @@ struct ast_variable *ast_http_get_post_vars( |
1285 | + return NULL; |
1286 | + } |
1287 | + |
1288 | ++ if (content_length > MAX_POST_CONTENT - 1) { |
1289 | ++ ast_log(LOG_WARNING, "Excessively long HTTP content. %d is greater than our max of %d\n", |
1290 | ++ content_length, MAX_POST_CONTENT); |
1291 | ++ ast_http_send(ser, AST_HTTP_POST, 413, "Request Entity Too Large", NULL, NULL, 0, 0); |
1292 | ++ return NULL; |
1293 | ++ } |
1294 | ++ |
1295 | + buf = ast_malloc(content_length + 1); |
1296 | + if (!buf) { |
1297 | + return NULL; |
1298 | +-- |
1299 | +1.7.10.4 |
1300 | + |
1301 | |
1302 | === added file 'debian/patches/AST-2013-003' |
1303 | --- debian/patches/AST-2013-003 1970-01-01 00:00:00 +0000 |
1304 | +++ debian/patches/AST-2013-003 2013-07-28 21:58:23 +0000 |
1305 | @@ -0,0 +1,370 @@ |
1306 | +From: Matthew Jordan <mjordan@digium.com> |
1307 | +Date: Wed, 27 Mar 2013 14:53:13 +0000 |
1308 | +Subject: AST-2013-003: Prevent username disclosure in SIP channel driver |
1309 | +Bug: https://issues.asterisk.org/jira/browse/ASTERISK-21013 |
1310 | +Origin: http://svnview.digium.com/svn/asterisk?view=rev&rev=383981 |
1311 | +CVE: CVE-2013-2264 |
1312 | + |
1313 | +When authenticating a SIP request with alwaysauthreject enabled, allowguest |
1314 | +disabled, and autocreatepeer disabled, Asterisk discloses whether a user |
1315 | +exists for INVITE, SUBSCRIBE, and REGISTER transactions in multiple ways. The |
1316 | +information is disclosed when: |
1317 | + * A "407 Proxy Authentication Required" response is sent instead of a |
1318 | + "401 Unauthorized" response |
1319 | + * The presence or absence of additional tags occurs at the end of "403 |
1320 | + Forbidden" (such as "(Bad Auth)") |
1321 | + * A "401 Unauthorized" response is sent instead of "403 Forbidden" response |
1322 | + after a retransmission |
1323 | + * Retransmission are sent when a matching peer did not exist, but not when a |
1324 | + matching peer did exist. |
1325 | + |
1326 | +This patch resolves these various vectors by ensuring that the responses sent |
1327 | +in all scenarios is the same, regardless of the presence of a matching peer. |
1328 | + |
1329 | +This issue was reported by Walter Doekes, OSSO B.V. A substantial portion of |
1330 | +the testing and the solution to this problem was done by Walter as well - a |
1331 | +huge thanks to his tireless efforts in finding all the ways in which this |
1332 | +setting didn't work, providing automated tests, and working with Kinsey on |
1333 | +getting this fixed. |
1334 | + |
1335 | +Patch slightly adapted due to irrelevant changes in r367362. |
1336 | + |
1337 | +See Also: http://downloads.asterisk.org/pub/security/AST-2013-003.html |
1338 | + |
1339 | +--- |
1340 | + channels/chan_sip.c | 128 ++++++++++++++++++++++++++++---------------- |
1341 | + channels/sip/include/sip.h | 1 - |
1342 | + 2 files changed, 83 insertions(+), 46 deletions(-) |
1343 | + |
1344 | +--- a/channels/chan_sip.c |
1345 | ++++ b/channels/chan_sip.c |
1346 | +@@ -1110,6 +1110,11 @@ static struct ao2_container *threadt; |
1347 | + static struct ao2_container *peers; |
1348 | + static struct ao2_container *peers_by_ip; |
1349 | + |
1350 | ++/*! \brief A bogus peer, to be used when authentication should fail */ |
1351 | ++static struct sip_peer *bogus_peer; |
1352 | ++/*! \brief We can recognise the bogus peer by this invalid MD5 hash */ |
1353 | ++#define BOGUS_PEER_MD5SECRET "intentionally_invalid_md5_string" |
1354 | ++ |
1355 | + /*! \brief The register list: Other SIP proxies we register with and receive calls from */ |
1356 | + static struct ast_register_list { |
1357 | + ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry); |
1358 | +@@ -1250,7 +1255,7 @@ static int transmit_response_with_unsupp |
1359 | + static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale); |
1360 | + static int transmit_provisional_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, int with_sdp); |
1361 | + static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable); |
1362 | +-static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct sip_request *req, enum xmittype reliable); |
1363 | ++static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable); |
1364 | + static int transmit_request(struct sip_pvt *p, int sipmethod, uint32_t seqno, enum xmittype reliable, int newbranch); |
1365 | + static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, uint32_t seqno, enum xmittype reliable, int newbranch); |
1366 | + static int transmit_publish(struct sip_epa_entry *epa_entry, enum sip_publish_type publish_type, const char * const explicit_uri); |
1367 | +@@ -14621,6 +14626,7 @@ static enum check_auth_result check_auth |
1368 | + char a1_hash[256]; |
1369 | + char resp_hash[256]=""; |
1370 | + char *c; |
1371 | ++ int is_bogus_peer = 0; |
1372 | + int wrongnonce = FALSE; |
1373 | + int good_response; |
1374 | + const char *usednonce = p->randdata; |
1375 | +@@ -14715,8 +14721,14 @@ static enum check_auth_result check_auth |
1376 | + } |
1377 | + } |
1378 | + |
1379 | ++ /* We cannot rely on the bogus_peer having a bad md5 value. Someone could |
1380 | ++ * use it to construct valid auth. */ |
1381 | ++ if (md5secret && strcmp(md5secret, BOGUS_PEER_MD5SECRET) == 0) { |
1382 | ++ is_bogus_peer = 1; |
1383 | ++ } |
1384 | ++ |
1385 | + /* Verify that digest username matches the username we auth as */ |
1386 | +- if (strcmp(username, keys[K_USER].s)) { |
1387 | ++ if (strcmp(username, keys[K_USER].s) && !is_bogus_peer) { |
1388 | + ast_log(LOG_WARNING, "username mismatch, have <%s>, digest has <%s>\n", |
1389 | + username, keys[K_USER].s); |
1390 | + /* Oops, we're trying something here */ |
1391 | +@@ -14755,7 +14767,8 @@ static enum check_auth_result check_auth |
1392 | + } |
1393 | + |
1394 | + good_response = keys[K_RESP].s && |
1395 | +- !strncasecmp(keys[K_RESP].s, resp_hash, strlen(resp_hash)); |
1396 | ++ !strncasecmp(keys[K_RESP].s, resp_hash, strlen(resp_hash)) && |
1397 | ++ !is_bogus_peer; /* lastly, check that the peer isn't the fake peer */ |
1398 | + if (wrongnonce) { |
1399 | + if (good_response) { |
1400 | + if (sipdebug) |
1401 | +@@ -14899,7 +14912,7 @@ static int cb_extensionstate(char *conte |
1402 | + /*! \brief Send a fake 401 Unauthorized response when the administrator |
1403 | + wants to hide the names of local devices from fishers |
1404 | + */ |
1405 | +-static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct sip_request *req, enum xmittype reliable) |
1406 | ++static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable) |
1407 | + { |
1408 | + /* We have to emulate EXACTLY what we'd get with a good peer |
1409 | + * and a bad password, or else we leak information. */ |
1410 | +@@ -14938,13 +14951,13 @@ static void transmit_fake_auth_response( |
1411 | + } |
1412 | + |
1413 | + if (!(buf = ast_str_thread_get(&check_auth_buf, CHECK_AUTH_BUF_INITLEN))) { |
1414 | +- transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq); |
1415 | ++ __transmit_response(p, "403 Forbidden", &p->initreq, reliable); |
1416 | + return; |
1417 | + } |
1418 | + |
1419 | + /* Make a copy of the response and parse it */ |
1420 | + if (ast_str_set(&buf, 0, "%s", authtoken) == AST_DYNSTR_BUILD_FAILED) { |
1421 | +- transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq); |
1422 | ++ __transmit_response(p, "403 Forbidden", &p->initreq, reliable); |
1423 | + return; |
1424 | + } |
1425 | + |
1426 | +@@ -14982,7 +14995,7 @@ static void transmit_fake_auth_response( |
1427 | + /* Schedule auto destroy in 32 seconds */ |
1428 | + sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); |
1429 | + } else { |
1430 | +- transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq); |
1431 | ++ __transmit_response(p, "403 Forbidden", &p->initreq, reliable); |
1432 | + } |
1433 | + } |
1434 | + |
1435 | +@@ -15077,7 +15090,7 @@ static enum check_auth_result register_v |
1436 | + if (!AST_LIST_EMPTY(&domain_list)) { |
1437 | + if (!check_sip_domain(domain, NULL, 0)) { |
1438 | + if (sip_cfg.alwaysauthreject) { |
1439 | +- transmit_fake_auth_response(p, SIP_REGISTER, &p->initreq, XMIT_UNRELIABLE); |
1440 | ++ transmit_fake_auth_response(p, &p->initreq, XMIT_UNRELIABLE); |
1441 | + } else { |
1442 | + transmit_response(p, "404 Not found (unknown domain)", &p->initreq); |
1443 | + } |
1444 | +@@ -15104,6 +15117,13 @@ static enum check_auth_result register_v |
1445 | + } |
1446 | + peer = find_peer(name, NULL, TRUE, FINDPEERS, FALSE, 0); |
1447 | + |
1448 | ++ /* If we don't want username disclosure, use the bogus_peer when a user |
1449 | ++ * is not found. */ |
1450 | ++ if (!peer && sip_cfg.alwaysauthreject && !sip_cfg.autocreatepeer) { |
1451 | ++ peer = bogus_peer; |
1452 | ++ ref_peer(peer, "register_verify: ref the bogus_peer"); |
1453 | ++ } |
1454 | ++ |
1455 | + if (!(peer && ast_apply_ha(peer->ha, addr))) { |
1456 | + /* Peer fails ACL check */ |
1457 | + if (peer) { |
1458 | +@@ -15183,7 +15203,7 @@ static enum check_auth_result register_v |
1459 | + switch (parse_register_contact(p, peer, req)) { |
1460 | + case PARSE_REGISTER_DENIED: |
1461 | + ast_log(LOG_WARNING, "Registration denied because of contact ACL\n"); |
1462 | +- transmit_response_with_date(p, "403 Forbidden (ACL)", req); |
1463 | ++ transmit_response_with_date(p, "403 Forbidden", req); |
1464 | + peer->lastmsgssent = -1; |
1465 | + res = 0; |
1466 | + break; |
1467 | +@@ -15218,7 +15238,7 @@ static enum check_auth_result register_v |
1468 | + switch (res) { |
1469 | + case AUTH_SECRET_FAILED: |
1470 | + /* Wrong password in authentication. Go away, don't try again until you fixed it */ |
1471 | +- transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq); |
1472 | ++ transmit_response(p, "403 Forbidden", &p->initreq); |
1473 | + if (global_authfailureevents) { |
1474 | + const char *peer_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr)); |
1475 | + const char *peer_port = ast_strdupa(ast_sockaddr_stringify_port(addr)); |
1476 | +@@ -15241,7 +15261,7 @@ static enum check_auth_result register_v |
1477 | + case AUTH_PEER_NOT_DYNAMIC: |
1478 | + case AUTH_ACL_FAILED: |
1479 | + if (sip_cfg.alwaysauthreject) { |
1480 | +- transmit_fake_auth_response(p, SIP_REGISTER, &p->initreq, XMIT_UNRELIABLE); |
1481 | ++ transmit_fake_auth_response(p, &p->initreq, XMIT_UNRELIABLE); |
1482 | + if (global_authfailureevents) { |
1483 | + const char *peer_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr)); |
1484 | + const char *peer_port = ast_strdupa(ast_sockaddr_stringify_port(addr)); |
1485 | +@@ -16242,7 +16262,19 @@ static enum check_auth_result check_peer |
1486 | + ast_verbose("No matching peer for '%s' from '%s'\n", |
1487 | + of, ast_sockaddr_stringify(&p->recv)); |
1488 | + } |
1489 | +- return AUTH_DONT_KNOW; |
1490 | ++ |
1491 | ++ /* If you don't mind, we can return 404s for devices that do |
1492 | ++ * not exist: username disclosure. If we allow guests, there |
1493 | ++ * is no way around that. */ |
1494 | ++ if (sip_cfg.allowguest || !sip_cfg.alwaysauthreject) { |
1495 | ++ return AUTH_DONT_KNOW; |
1496 | ++ } |
1497 | ++ |
1498 | ++ /* If you do mind, we use a peer that will never authenticate. |
1499 | ++ * This ensures that we follow the same code path as regular |
1500 | ++ * auth: less chance for username disclosure. */ |
1501 | ++ peer = bogus_peer; |
1502 | ++ ref_peer(peer, "ref_peer: check_peer_ok: must ref bogus_peer so unreffing it does not fail"); |
1503 | + } |
1504 | + |
1505 | + if (!ast_apply_ha(peer->ha, addr)) { |
1506 | +@@ -16250,9 +16282,10 @@ static enum check_auth_result check_peer |
1507 | + unref_peer(peer, "unref_peer: check_peer_ok: from find_peer call, early return of AUTH_ACL_FAILED"); |
1508 | + return AUTH_ACL_FAILED; |
1509 | + } |
1510 | +- if (debug) |
1511 | ++ if (debug && peer != bogus_peer) { |
1512 | + ast_verbose("Found peer '%s' for '%s' from %s\n", |
1513 | + peer->name, of, ast_sockaddr_stringify(&p->recv)); |
1514 | ++ } |
1515 | + |
1516 | + /* XXX what about p->prefs = peer->prefs; ? */ |
1517 | + /* Set Frame packetization */ |
1518 | +@@ -16517,8 +16550,6 @@ static enum check_auth_result check_user |
1519 | + } else { |
1520 | + res = AUTH_RTP_FAILED; |
1521 | + } |
1522 | +- } else if (sip_cfg.alwaysauthreject) { |
1523 | +- res = AUTH_FAKE_AUTH; /* reject with fake authorization request */ |
1524 | + } else { |
1525 | + res = AUTH_SECRET_FAILED; /* we don't want any guests, authentication will fail */ |
1526 | + } |
1527 | +@@ -22225,13 +22256,8 @@ static int handle_request_options(struct |
1528 | + return 0; |
1529 | + } |
1530 | + if (res < 0) { /* Something failed in authentication */ |
1531 | +- if (res == AUTH_FAKE_AUTH) { |
1532 | +- ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From")); |
1533 | +- transmit_fake_auth_response(p, SIP_OPTIONS, req, XMIT_UNRELIABLE); |
1534 | +- } else { |
1535 | +- ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From")); |
1536 | +- transmit_response(p, "403 Forbidden", req); |
1537 | +- } |
1538 | ++ ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From")); |
1539 | ++ transmit_response(p, "403 Forbidden", req); |
1540 | + sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); |
1541 | + return 0; |
1542 | + } |
1543 | +@@ -22896,13 +22922,8 @@ static int handle_request_invite(struct |
1544 | + goto request_invite_cleanup; |
1545 | + } |
1546 | + if (res < 0) { /* Something failed in authentication */ |
1547 | +- if (res == AUTH_FAKE_AUTH) { |
1548 | +- ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From")); |
1549 | +- transmit_fake_auth_response(p, SIP_INVITE, req, XMIT_RELIABLE); |
1550 | +- } else { |
1551 | +- ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From")); |
1552 | +- transmit_response_reliable(p, "403 Forbidden", req); |
1553 | +- } |
1554 | ++ ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From")); |
1555 | ++ transmit_response_reliable(p, "403 Forbidden", req); |
1556 | + p->invitestate = INV_COMPLETED; |
1557 | + sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); |
1558 | + res = 0; |
1559 | +@@ -24712,18 +24733,13 @@ static int handle_request_publish(struct |
1560 | + return -1; |
1561 | + } |
1562 | + |
1563 | +- auth_result = check_user(p, req, SIP_PUBLISH, uri, XMIT_RELIABLE, addr); |
1564 | ++ auth_result = check_user(p, req, SIP_PUBLISH, uri, XMIT_UNRELIABLE, addr); |
1565 | + if (auth_result == AUTH_CHALLENGE_SENT) { |
1566 | + p->lastinvite = seqno; |
1567 | + return 0; |
1568 | + } else if (auth_result < 0) { |
1569 | +- if (auth_result == AUTH_FAKE_AUTH) { |
1570 | +- ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From")); |
1571 | +- transmit_fake_auth_response(p, SIP_INVITE, req, XMIT_RELIABLE); |
1572 | +- } else { |
1573 | +- ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From")); |
1574 | +- transmit_response_reliable(p, "403 Forbidden", req); |
1575 | +- } |
1576 | ++ ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From")); |
1577 | ++ transmit_response(p, "403 Forbidden", req); |
1578 | + sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); |
1579 | + ast_string_field_set(p, theirtag, NULL); |
1580 | + return 0; |
1581 | +@@ -24938,19 +24954,14 @@ static int handle_request_subscribe(stru |
1582 | + * use if !req->ignore, because then we'll end up sending |
1583 | + * a 200 OK if someone retransmits without sending auth */ |
1584 | + if (p->subscribed == NONE || resubscribe) { |
1585 | +- res = check_user_full(p, req, SIP_SUBSCRIBE, e, 0, addr, &authpeer); |
1586 | ++ res = check_user_full(p, req, SIP_SUBSCRIBE, e, XMIT_UNRELIABLE, addr, &authpeer); |
1587 | + |
1588 | + /* if an authentication response was sent, we are done here */ |
1589 | + if (res == AUTH_CHALLENGE_SENT) /* authpeer = NULL here */ |
1590 | + return 0; |
1591 | + if (res != AUTH_SUCCESSFUL) { |
1592 | +- if (res == AUTH_FAKE_AUTH) { |
1593 | +- ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From")); |
1594 | +- transmit_fake_auth_response(p, SIP_SUBSCRIBE, req, XMIT_UNRELIABLE); |
1595 | +- } else { |
1596 | +- ast_log(LOG_NOTICE, "Failed to authenticate device %s for SUBSCRIBE\n", get_header(req, "From")); |
1597 | +- transmit_response_reliable(p, "403 Forbidden", req); |
1598 | +- } |
1599 | ++ ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From")); |
1600 | ++ transmit_response(p, "403 Forbidden", req); |
1601 | + |
1602 | + pvt_set_needdestroy(p, "authentication failed"); |
1603 | + return 0; |
1604 | +@@ -29988,6 +29999,7 @@ static int sip_do_reload(enum channelrel |
1605 | + /*! \brief Force reload of module from cli */ |
1606 | + static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
1607 | + { |
1608 | ++ static struct sip_peer *tmp_peer, *new_peer; |
1609 | + |
1610 | + switch (cmd) { |
1611 | + case CLI_INIT: |
1612 | +@@ -30010,6 +30022,18 @@ static char *sip_reload(struct ast_cli_e |
1613 | + ast_mutex_unlock(&sip_reload_lock); |
1614 | + restart_monitor(); |
1615 | + |
1616 | ++ tmp_peer = bogus_peer; |
1617 | ++ /* Create new bogus peer possibly with new global settings. */ |
1618 | ++ if ((new_peer = temp_peer("(bogus_peer)"))) { |
1619 | ++ ast_string_field_set(new_peer, md5secret, BOGUS_PEER_MD5SECRET); |
1620 | ++ ast_clear_flag(&new_peer->flags[0], SIP_INSECURE); |
1621 | ++ bogus_peer = new_peer; |
1622 | ++ ao2_t_ref(tmp_peer, -1, "unref the old bogus_peer during reload"); |
1623 | ++ } else { |
1624 | ++ ast_log(LOG_ERROR, "Could not update the fake authentication peer.\n"); |
1625 | ++ /* You probably have bigger (memory?) issues to worry about though.. */ |
1626 | ++ } |
1627 | ++ |
1628 | + return CLI_SUCCESS; |
1629 | + } |
1630 | + |
1631 | +@@ -31130,6 +31154,17 @@ static int load_module(void) |
1632 | + return AST_MODULE_LOAD_DECLINE; |
1633 | + } |
1634 | + |
1635 | ++ /* Initialize bogus peer. Can be done first after reload_config() */ |
1636 | ++ if (!(bogus_peer = temp_peer("(bogus_peer)"))) { |
1637 | ++ ast_log(LOG_ERROR, "Unable to create bogus_peer for authentication\n"); |
1638 | ++ io_context_destroy(io); |
1639 | ++ sched_context_destroy(sched); |
1640 | ++ return AST_MODULE_LOAD_FAILURE; |
1641 | ++ } |
1642 | ++ /* Make sure the auth will always fail. */ |
1643 | ++ ast_string_field_set(bogus_peer, md5secret, BOGUS_PEER_MD5SECRET); |
1644 | ++ ast_clear_flag(&bogus_peer->flags[0], SIP_INSECURE); |
1645 | ++ |
1646 | + /* Prepare the version that does not require DTMF BEGIN frames. |
1647 | + * We need to use tricks such as memcpy and casts because the variable |
1648 | + * has const fields. |
1649 | +@@ -31140,6 +31175,7 @@ static int load_module(void) |
1650 | + /* Make sure we can register our sip channel type */ |
1651 | + if (ast_channel_register(&sip_tech)) { |
1652 | + ast_log(LOG_ERROR, "Unable to register channel type 'SIP'\n"); |
1653 | ++ ao2_t_ref(bogus_peer, -1, "unref the bogus_peer"); |
1654 | + io_context_destroy(io); |
1655 | + sched_context_destroy(sched); |
1656 | + return AST_MODULE_LOAD_FAILURE; |
1657 | +@@ -31378,6 +31414,8 @@ static int unload_module(void) |
1658 | + ast_debug(2, "TCP/TLS thread container did not become empty :(\n"); |
1659 | + } |
1660 | + |
1661 | ++ ao2_t_ref(bogus_peer, -1, "unref the bogus_peer"); |
1662 | ++ |
1663 | + ao2_t_ref(peers, -1, "unref the peers table"); |
1664 | + ao2_t_ref(peers_by_ip, -1, "unref the peers_by_ip table"); |
1665 | + ao2_t_ref(dialogs, -1, "unref the dialogs table"); |
1666 | +--- a/channels/sip/include/sip.h |
1667 | ++++ b/channels/sip/include/sip.h |
1668 | +@@ -470,7 +470,6 @@ enum check_auth_result { |
1669 | + AUTH_SECRET_FAILED = -1, |
1670 | + AUTH_USERNAME_MISMATCH = -2, |
1671 | + AUTH_NOT_FOUND = -3, /*!< returned by register_verify */ |
1672 | +- AUTH_FAKE_AUTH = -4, |
1673 | + AUTH_UNKNOWN_DOMAIN = -5, |
1674 | + AUTH_PEER_NOT_DYNAMIC = -6, |
1675 | + AUTH_ACL_FAILED = -7, |
1676 | |
1677 | === modified file 'debian/patches/armhf-fixes' |
1678 | --- debian/patches/armhf-fixes 2012-04-24 22:15:54 +0000 |
1679 | +++ debian/patches/armhf-fixes 2013-07-28 21:58:23 +0000 |
1680 | @@ -1,6 +1,5 @@ |
1681 | Author: Adam Conrad <adconrad@ubuntu.com> |
1682 | - |
1683 | -Fix a few places where armhf is misdetected. |
1684 | +Description: Fix a few places where armhf is misdetected. Flatten linux-gnueabihf in configure to linux-gnu, in the same way that's already done for linux-gnueabi. |
1685 | |
1686 | --- x/configure.ac 2012-01-12 08:24:38.000000000 -0700 |
1687 | +++ x/configure.ac 2012-01-12 08:59:45.647736713 -0700 |
1688 | |
1689 | === added file 'debian/patches/bluetooth_bind' |
1690 | --- debian/patches/bluetooth_bind 1970-01-01 00:00:00 +0000 |
1691 | +++ debian/patches/bluetooth_bind 2013-07-28 21:58:23 +0000 |
1692 | @@ -0,0 +1,30 @@ |
1693 | +From: Matthew Jordan <mjordan@digium.com> |
1694 | +Date: Thu, 17 Jan 2013 02:28:31 +0000 |
1695 | +Subject: Fix issue where chan_mobile fails to bind to first available port |
1696 | +Bug: https://issues.asterisk.org/jira/browse/ASTERISK-16357 |
1697 | +Origin: http://svnview.digium.com/svn/asterisk?view=rev&rev=379342 |
1698 | + |
1699 | +Per the bluez API, in order to bind to the first available port, the rc_channel |
1700 | +field of the socket addressing structure used to bind the socket should be set |
1701 | +to 0. Previously, Asterisk had set the rc_channel field set to 1, causing it |
1702 | +to connect to whatever happens to be on port 1. |
1703 | + |
1704 | +We could probably not explicitly set rc_channel to 0 since we memset the struct |
1705 | +earlier, but explicitly setting it will hopefully prevent someone from coming |
1706 | +in and setting it to some explicit port in the future. |
1707 | + |
1708 | +--- |
1709 | + addons/chan_mobile.c | 2 +- |
1710 | + 1 file changed, 1 insertion(+), 1 deletion(-) |
1711 | + |
1712 | +--- a/addons/chan_mobile.c |
1713 | ++++ b/addons/chan_mobile.c |
1714 | +@@ -1370,7 +1370,7 @@ static int rfcomm_connect(bdaddr_t src, |
1715 | + memset(&addr, 0, sizeof(addr)); |
1716 | + addr.rc_family = AF_BLUETOOTH; |
1717 | + bacpy(&addr.rc_bdaddr, &src); |
1718 | +- addr.rc_channel = (uint8_t) 1; |
1719 | ++ addr.rc_channel = (uint8_t) 0; |
1720 | + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { |
1721 | + ast_debug(1, "bind() failed (%d).\n", errno); |
1722 | + close(s); |
1723 | |
1724 | === modified file 'debian/patches/series' |
1725 | --- debian/patches/series 2012-09-08 12:38:06 +0000 |
1726 | +++ debian/patches/series 2013-07-28 21:58:23 +0000 |
1727 | @@ -29,3 +29,8 @@ |
1728 | |
1729 | AST-2012-012 |
1730 | AST-2012-013 |
1731 | +AST-2012-014 |
1732 | +AST-2012-015 |
1733 | +AST-2013-002 |
1734 | +AST-2013-003 |
1735 | +bluetooth_bind |
Thanks. Uploaded.