Merge lp:~davewalker/ubuntu/lucid/asterisk/lp_705014 into lp:ubuntu/lucid-proposed/asterisk

Proposed by Dave Walker
Status: Needs review
Proposed branch: lp:~davewalker/ubuntu/lucid/asterisk/lp_705014
Merge into: lp:ubuntu/lucid-proposed/asterisk
Diff against target: 1986 lines (+1908/-15)
8 files modified
.pc/.quilt_patches (+1/-0)
.pc/.quilt_series (+1/-0)
.pc/AST-2011-001-1.6.2/main/utils.c (+1828/-0)
.pc/applied-patches (+1/-0)
debian/changelog (+10/-0)
debian/patches/AST-2011-001-1.6.2 (+52/-0)
debian/patches/series (+1/-0)
main/utils.c (+14/-15)
To merge this branch: bzr merge lp:~davewalker/ubuntu/lucid/asterisk/lp_705014
Reviewer Review Type Date Requested Status
Jamie Strandboge Approve
Review via email: mp+47003@code.launchpad.net

This proposal supersedes a proposal from 2011-01-20.

Description of the change

Waiting on 1:1.6.2.5-0ubuntu1.2 to clear -proposed, which has verification-done.

Re-targeted against -proposed bzr branch to give a better diff.

To post a comment you must log in.
Revision history for this message
Jamie Strandboge (jdstrand) wrote :

Thanks!

review: Approve
Revision history for this message
Jamie Strandboge (jdstrand) : Posted in a previous version of this proposal
review: Disapprove

Unmerged revisions

59. By Dave Walker

* SECURITY UPDATE: Stack buffer overflow in SIP channel driver. (LP: #705014)
  - debian/patches/AST-2011-001-1.6.2: The size of the output buffer passed
    to the ast_uri_encode function is now properly respected in main/utils.c.
    Patch courtesy of upstream.
  - CVE-2011-0495

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file '.pc/.quilt_patches'
--- .pc/.quilt_patches 1970-01-01 00:00:00 +0000
+++ .pc/.quilt_patches 2011-01-20 23:58:58 +0000
@@ -0,0 +1,1 @@
1debian/patches
02
=== added file '.pc/.quilt_series'
--- .pc/.quilt_series 1970-01-01 00:00:00 +0000
+++ .pc/.quilt_series 2011-01-20 23:58:58 +0000
@@ -0,0 +1,1 @@
1series
02
=== added directory '.pc/AST-2011-001-1.6.2'
=== added file '.pc/AST-2011-001-1.6.2/.timestamp'
=== added directory '.pc/AST-2011-001-1.6.2/main'
=== added file '.pc/AST-2011-001-1.6.2/main/utils.c'
--- .pc/AST-2011-001-1.6.2/main/utils.c 1970-01-01 00:00:00 +0000
+++ .pc/AST-2011-001-1.6.2/main/utils.c 2011-01-20 23:58:58 +0000
@@ -0,0 +1,1828 @@
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, Digium, Inc.
5 *
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
11 *
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
15 */
16
17/*! \file
18 *
19 * \brief Utility functions
20 *
21 * \note These are important for portability and security,
22 * so please use them in favour of other routines.
23 * Please consult the CODING GUIDELINES for more information.
24 */
25
26#include "asterisk.h"
27
28ASTERISK_FILE_VERSION(__FILE__, "$Revision: 237743 $")
29
30#include <ctype.h>
31#include <sys/stat.h>
32
33#ifdef HAVE_DEV_URANDOM
34#include <fcntl.h>
35#endif
36
37#include "asterisk/network.h"
38
39#define AST_API_MODULE /* ensure that inlinable API functions will be built in lock.h if required */
40#include "asterisk/lock.h"
41#include "asterisk/io.h"
42#include "asterisk/md5.h"
43#include "asterisk/sha1.h"
44#include "asterisk/cli.h"
45#include "asterisk/linkedlists.h"
46
47#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
48#include "asterisk/strings.h"
49
50#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
51#include "asterisk/time.h"
52
53#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
54#include "asterisk/stringfields.h"
55
56#define AST_API_MODULE /* ensure that inlinable API functions will be built in this module if required */
57#include "asterisk/utils.h"
58
59#define AST_API_MODULE
60#include "asterisk/threadstorage.h"
61
62#define AST_API_MODULE
63#include "asterisk/config.h"
64
65static char base64[64];
66static char b2a[256];
67
68AST_THREADSTORAGE(inet_ntoa_buf);
69
70#if !defined(HAVE_GETHOSTBYNAME_R_5) && !defined(HAVE_GETHOSTBYNAME_R_6)
71
72#define ERANGE 34 /*!< duh? ERANGE value copied from web... */
73#undef gethostbyname
74
75AST_MUTEX_DEFINE_STATIC(__mutex);
76
77/*! \brief Reentrant replacement for gethostbyname for BSD-based systems.
78\note This
79routine is derived from code originally written and placed in the public
80domain by Enzo Michelangeli <em@em.no-ip.com> */
81
82static int gethostbyname_r (const char *name, struct hostent *ret, char *buf,
83 size_t buflen, struct hostent **result,
84 int *h_errnop)
85{
86 int hsave;
87 struct hostent *ph;
88 ast_mutex_lock(&__mutex); /* begin critical area */
89 hsave = h_errno;
90
91 ph = gethostbyname(name);
92 *h_errnop = h_errno; /* copy h_errno to *h_herrnop */
93 if (ph == NULL) {
94 *result = NULL;
95 } else {
96 char **p, **q;
97 char *pbuf;
98 int nbytes = 0;
99 int naddr = 0, naliases = 0;
100 /* determine if we have enough space in buf */
101
102 /* count how many addresses */
103 for (p = ph->h_addr_list; *p != 0; p++) {
104 nbytes += ph->h_length; /* addresses */
105 nbytes += sizeof(*p); /* pointers */
106 naddr++;
107 }
108 nbytes += sizeof(*p); /* one more for the terminating NULL */
109
110 /* count how many aliases, and total length of strings */
111 for (p = ph->h_aliases; *p != 0; p++) {
112 nbytes += (strlen(*p)+1); /* aliases */
113 nbytes += sizeof(*p); /* pointers */
114 naliases++;
115 }
116 nbytes += sizeof(*p); /* one more for the terminating NULL */
117
118 /* here nbytes is the number of bytes required in buffer */
119 /* as a terminator must be there, the minimum value is ph->h_length */
120 if (nbytes > buflen) {
121 *result = NULL;
122 ast_mutex_unlock(&__mutex); /* end critical area */
123 return ERANGE; /* not enough space in buf!! */
124 }
125
126 /* There is enough space. Now we need to do a deep copy! */
127 /* Allocation in buffer:
128 from [0] to [(naddr-1) * sizeof(*p)]:
129 pointers to addresses
130 at [naddr * sizeof(*p)]:
131 NULL
132 from [(naddr+1) * sizeof(*p)] to [(naddr+naliases) * sizeof(*p)] :
133 pointers to aliases
134 at [(naddr+naliases+1) * sizeof(*p)]:
135 NULL
136 then naddr addresses (fixed length), and naliases aliases (asciiz).
137 */
138
139 *ret = *ph; /* copy whole structure (not its address!) */
140
141 /* copy addresses */
142 q = (char **)buf; /* pointer to pointers area (type: char **) */
143 ret->h_addr_list = q; /* update pointer to address list */
144 pbuf = buf + ((naddr + naliases + 2) * sizeof(*p)); /* skip that area */
145 for (p = ph->h_addr_list; *p != 0; p++) {
146 memcpy(pbuf, *p, ph->h_length); /* copy address bytes */
147 *q++ = pbuf; /* the pointer is the one inside buf... */
148 pbuf += ph->h_length; /* advance pbuf */
149 }
150 *q++ = NULL; /* address list terminator */
151
152 /* copy aliases */
153 ret->h_aliases = q; /* update pointer to aliases list */
154 for (p = ph->h_aliases; *p != 0; p++) {
155 strcpy(pbuf, *p); /* copy alias strings */
156 *q++ = pbuf; /* the pointer is the one inside buf... */
157 pbuf += strlen(*p); /* advance pbuf */
158 *pbuf++ = 0; /* string terminator */
159 }
160 *q++ = NULL; /* terminator */
161
162 strcpy(pbuf, ph->h_name); /* copy alias strings */
163 ret->h_name = pbuf;
164 pbuf += strlen(ph->h_name); /* advance pbuf */
165 *pbuf++ = 0; /* string terminator */
166
167 *result = ret; /* and let *result point to structure */
168
169 }
170 h_errno = hsave; /* restore h_errno */
171 ast_mutex_unlock(&__mutex); /* end critical area */
172
173 return (*result == NULL); /* return 0 on success, non-zero on error */
174}
175
176
177#endif
178
179/*! \brief Re-entrant (thread safe) version of gethostbyname that replaces the
180 standard gethostbyname (which is not thread safe)
181*/
182struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp)
183{
184 int res;
185 int herrno;
186 int dots = 0;
187 const char *s;
188 struct hostent *result = NULL;
189 /* Although it is perfectly legitimate to lookup a pure integer, for
190 the sake of the sanity of people who like to name their peers as
191 integers, we break with tradition and refuse to look up a
192 pure integer */
193 s = host;
194 res = 0;
195 while (s && *s) {
196 if (*s == '.')
197 dots++;
198 else if (!isdigit(*s))
199 break;
200 s++;
201 }
202 if (!s || !*s) {
203 /* Forge a reply for IP's to avoid octal IP's being interpreted as octal */
204 if (dots != 3)
205 return NULL;
206 memset(hp, 0, sizeof(struct ast_hostent));
207 hp->hp.h_addrtype = AF_INET;
208 hp->hp.h_addr_list = (void *) hp->buf;
209 hp->hp.h_addr = hp->buf + sizeof(void *);
210 if (inet_pton(AF_INET, host, hp->hp.h_addr) > 0)
211 return &hp->hp;
212 return NULL;
213
214 }
215#ifdef HAVE_GETHOSTBYNAME_R_5
216 result = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &herrno);
217
218 if (!result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
219 return NULL;
220#else
221 res = gethostbyname_r(host, &hp->hp, hp->buf, sizeof(hp->buf), &result, &herrno);
222
223 if (res || !result || !hp->hp.h_addr_list || !hp->hp.h_addr_list[0])
224 return NULL;
225#endif
226 return &hp->hp;
227}
228
229/*! \brief Produce 32 char MD5 hash of value. */
230void ast_md5_hash(char *output, char *input)
231{
232 struct MD5Context md5;
233 unsigned char digest[16];
234 char *ptr;
235 int x;
236
237 MD5Init(&md5);
238 MD5Update(&md5, (unsigned char *)input, strlen(input));
239 MD5Final(digest, &md5);
240 ptr = output;
241 for (x = 0; x < 16; x++)
242 ptr += sprintf(ptr, "%2.2x", digest[x]);
243}
244
245/*! \brief Produce 40 char SHA1 hash of value. */
246void ast_sha1_hash(char *output, char *input)
247{
248 struct SHA1Context sha;
249 char *ptr;
250 int x;
251 uint8_t Message_Digest[20];
252
253 SHA1Reset(&sha);
254
255 SHA1Input(&sha, (const unsigned char *) input, strlen(input));
256
257 SHA1Result(&sha, Message_Digest);
258 ptr = output;
259 for (x = 0; x < 20; x++)
260 ptr += sprintf(ptr, "%2.2x", Message_Digest[x]);
261}
262
263/*! \brief decode BASE64 encoded text */
264int ast_base64decode(unsigned char *dst, const char *src, int max)
265{
266 int cnt = 0;
267 unsigned int byte = 0;
268 unsigned int bits = 0;
269 int incnt = 0;
270 while(*src && *src != '=' && (cnt < max)) {
271 /* Shift in 6 bits of input */
272 byte <<= 6;
273 byte |= (b2a[(int)(*src)]) & 0x3f;
274 bits += 6;
275 src++;
276 incnt++;
277 /* If we have at least 8 bits left over, take that character
278 off the top */
279 if (bits >= 8) {
280 bits -= 8;
281 *dst = (byte >> bits) & 0xff;
282 dst++;
283 cnt++;
284 }
285 }
286 /* Dont worry about left over bits, they're extra anyway */
287 return cnt;
288}
289
290/*! \brief encode text to BASE64 coding */
291int ast_base64encode_full(char *dst, const unsigned char *src, int srclen, int max, int linebreaks)
292{
293 int cnt = 0;
294 int col = 0;
295 unsigned int byte = 0;
296 int bits = 0;
297 int cntin = 0;
298 /* Reserve space for null byte at end of string */
299 max--;
300 while ((cntin < srclen) && (cnt < max)) {
301 byte <<= 8;
302 byte |= *(src++);
303 bits += 8;
304 cntin++;
305 if ((bits == 24) && (cnt + 4 <= max)) {
306 *dst++ = base64[(byte >> 18) & 0x3f];
307 *dst++ = base64[(byte >> 12) & 0x3f];
308 *dst++ = base64[(byte >> 6) & 0x3f];
309 *dst++ = base64[byte & 0x3f];
310 cnt += 4;
311 col += 4;
312 bits = 0;
313 byte = 0;
314 }
315 if (linebreaks && (cnt < max) && (col == 64)) {
316 *dst++ = '\n';
317 cnt++;
318 col = 0;
319 }
320 }
321 if (bits && (cnt + 4 <= max)) {
322 /* Add one last character for the remaining bits,
323 padding the rest with 0 */
324 byte <<= 24 - bits;
325 *dst++ = base64[(byte >> 18) & 0x3f];
326 *dst++ = base64[(byte >> 12) & 0x3f];
327 if (bits == 16)
328 *dst++ = base64[(byte >> 6) & 0x3f];
329 else
330 *dst++ = '=';
331 *dst++ = '=';
332 cnt += 4;
333 }
334 if (linebreaks && (cnt < max)) {
335 *dst++ = '\n';
336 cnt++;
337 }
338 *dst = '\0';
339 return cnt;
340}
341
342int ast_base64encode(char *dst, const unsigned char *src, int srclen, int max)
343{
344 return ast_base64encode_full(dst, src, srclen, max, 0);
345}
346
347static void base64_init(void)
348{
349 int x;
350 memset(b2a, -1, sizeof(b2a));
351 /* Initialize base-64 Conversion table */
352 for (x = 0; x < 26; x++) {
353 /* A-Z */
354 base64[x] = 'A' + x;
355 b2a['A' + x] = x;
356 /* a-z */
357 base64[x + 26] = 'a' + x;
358 b2a['a' + x] = x + 26;
359 /* 0-9 */
360 if (x < 10) {
361 base64[x + 52] = '0' + x;
362 b2a['0' + x] = x + 52;
363 }
364 }
365 base64[62] = '+';
366 base64[63] = '/';
367 b2a[(int)'+'] = 62;
368 b2a[(int)'/'] = 63;
369}
370
371/*! \brief ast_uri_encode: Turn text string to URI-encoded %XX version
372\note At this point, we're converting from ISO-8859-x (8-bit), not UTF8
373 as in the SIP protocol spec
374 If doreserved == 1 we will convert reserved characters also.
375 RFC 2396, section 2.4
376 outbuf needs to have more memory allocated than the instring
377 to have room for the expansion. Every char that is converted
378 is replaced by three ASCII characters.
379
380 Note: The doreserved option is needed for replaces header in
381 SIP transfers.
382*/
383char *ast_uri_encode(const char *string, char *outbuf, int buflen, int doreserved)
384{
385 char *reserved = ";/?:@&=+$,# "; /* Reserved chars */
386
387 const char *ptr = string; /* Start with the string */
388 char *out = NULL;
389 char *buf = NULL;
390
391 ast_copy_string(outbuf, string, buflen);
392
393 /* If there's no characters to convert, just go through and don't do anything */
394 while (*ptr) {
395 if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) {
396 /* Oops, we need to start working here */
397 if (!buf) {
398 buf = outbuf;
399 out = buf + (ptr - string) ; /* Set output ptr */
400 }
401 out += sprintf(out, "%%%02x", (unsigned char) *ptr);
402 } else if (buf) {
403 *out = *ptr; /* Continue copying the string */
404 out++;
405 }
406 ptr++;
407 }
408 if (buf)
409 *out = '\0';
410 return outbuf;
411}
412
413/*! \brief ast_uri_decode: Decode SIP URI, URN, URL (overwrite the string) */
414void ast_uri_decode(char *s)
415{
416 char *o;
417 unsigned int tmp;
418
419 for (o = s; *s; s++, o++) {
420 if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) {
421 /* have '%', two chars and correct parsing */
422 *o = tmp;
423 s += 2; /* Will be incremented once more when we break out */
424 } else /* all other cases, just copy */
425 *o = *s;
426 }
427 *o = '\0';
428}
429
430/*! \brief ast_inet_ntoa: Recursive thread safe replacement of inet_ntoa */
431const char *ast_inet_ntoa(struct in_addr ia)
432{
433 char *buf;
434
435 if (!(buf = ast_threadstorage_get(&inet_ntoa_buf, INET_ADDRSTRLEN)))
436 return "";
437
438 return inet_ntop(AF_INET, &ia, buf, INET_ADDRSTRLEN);
439}
440
441#ifdef HAVE_DEV_URANDOM
442static int dev_urandom_fd;
443#endif
444
445#ifndef __linux__
446#undef pthread_create /* For ast_pthread_create function only */
447#endif /* !__linux__ */
448
449#if !defined(LOW_MEMORY)
450
451#ifdef DEBUG_THREADS
452
453/*! \brief A reasonable maximum number of locks a thread would be holding ... */
454#define AST_MAX_LOCKS 64
455
456/* Allow direct use of pthread_mutex_t and friends */
457#undef pthread_mutex_t
458#undef pthread_mutex_lock
459#undef pthread_mutex_unlock
460#undef pthread_mutex_init
461#undef pthread_mutex_destroy
462
463/*!
464 * \brief Keep track of which locks a thread holds
465 *
466 * There is an instance of this struct for every active thread
467 */
468struct thr_lock_info {
469 /*! The thread's ID */
470 pthread_t thread_id;
471 /*! The thread name which includes where the thread was started */
472 const char *thread_name;
473 /*! This is the actual container of info for what locks this thread holds */
474 struct {
475 const char *file;
476 int line_num;
477 const char *func;
478 const char *lock_name;
479 void *lock_addr;
480 int times_locked;
481 enum ast_lock_type type;
482 /*! This thread is waiting on this lock */
483 int pending:2;
484#ifdef HAVE_BKTR
485 struct ast_bt *backtrace;
486#endif
487 } locks[AST_MAX_LOCKS];
488 /*! This is the number of locks currently held by this thread.
489 * The index (num_locks - 1) has the info on the last one in the
490 * locks member */
491 unsigned int num_locks;
492 /*! Protects the contents of the locks member
493 * Intentionally not ast_mutex_t */
494 pthread_mutex_t lock;
495 AST_LIST_ENTRY(thr_lock_info) entry;
496};
497
498/*!
499 * \brief Locked when accessing the lock_infos list
500 */
501AST_MUTEX_DEFINE_STATIC(lock_infos_lock);
502/*!
503 * \brief A list of each thread's lock info
504 */
505static AST_LIST_HEAD_NOLOCK_STATIC(lock_infos, thr_lock_info);
506
507/*!
508 * \brief Destroy a thread's lock info
509 *
510 * This gets called automatically when the thread stops
511 */
512static void lock_info_destroy(void *data)
513{
514 struct thr_lock_info *lock_info = data;
515 int i;
516
517 pthread_mutex_lock(&lock_infos_lock.mutex);
518 AST_LIST_REMOVE(&lock_infos, lock_info, entry);
519 pthread_mutex_unlock(&lock_infos_lock.mutex);
520
521
522 for (i = 0; i < lock_info->num_locks; i++) {
523 if (lock_info->locks[i].pending == -1) {
524 /* This just means that the last lock this thread went for was by
525 * using trylock, and it failed. This is fine. */
526 break;
527 }
528
529 ast_log(LOG_ERROR,
530 "Thread '%s' still has a lock! - '%s' (%p) from '%s' in %s:%d!\n",
531 lock_info->thread_name,
532 lock_info->locks[i].lock_name,
533 lock_info->locks[i].lock_addr,
534 lock_info->locks[i].func,
535 lock_info->locks[i].file,
536 lock_info->locks[i].line_num
537 );
538 }
539
540 pthread_mutex_destroy(&lock_info->lock);
541 if (lock_info->thread_name)
542 free((void *) lock_info->thread_name);
543 free(lock_info);
544}
545
546/*!
547 * \brief The thread storage key for per-thread lock info
548 */
549AST_THREADSTORAGE_CUSTOM(thread_lock_info, NULL, lock_info_destroy);
550#ifdef HAVE_BKTR
551void ast_store_lock_info(enum ast_lock_type type, const char *filename,
552 int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
553#else
554void ast_store_lock_info(enum ast_lock_type type, const char *filename,
555 int line_num, const char *func, const char *lock_name, void *lock_addr)
556#endif
557{
558 struct thr_lock_info *lock_info;
559 int i;
560
561 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
562 return;
563
564 pthread_mutex_lock(&lock_info->lock);
565
566 for (i = 0; i < lock_info->num_locks; i++) {
567 if (lock_info->locks[i].lock_addr == lock_addr) {
568 lock_info->locks[i].times_locked++;
569#ifdef HAVE_BKTR
570 lock_info->locks[i].backtrace = bt;
571#endif
572 pthread_mutex_unlock(&lock_info->lock);
573 return;
574 }
575 }
576
577 if (lock_info->num_locks == AST_MAX_LOCKS) {
578 /* Can't use ast_log here, because it will cause infinite recursion */
579 fprintf(stderr, "XXX ERROR XXX A thread holds more locks than '%d'."
580 " Increase AST_MAX_LOCKS!\n", AST_MAX_LOCKS);
581 pthread_mutex_unlock(&lock_info->lock);
582 return;
583 }
584
585 if (i && lock_info->locks[i - 1].pending == -1) {
586 /* The last lock on the list was one that this thread tried to lock but
587 * failed at doing so. It has now moved on to something else, so remove
588 * the old lock from the list. */
589 i--;
590 lock_info->num_locks--;
591 memset(&lock_info->locks[i], 0, sizeof(lock_info->locks[0]));
592 }
593
594 lock_info->locks[i].file = filename;
595 lock_info->locks[i].line_num = line_num;
596 lock_info->locks[i].func = func;
597 lock_info->locks[i].lock_name = lock_name;
598 lock_info->locks[i].lock_addr = lock_addr;
599 lock_info->locks[i].times_locked = 1;
600 lock_info->locks[i].type = type;
601 lock_info->locks[i].pending = 1;
602#ifdef HAVE_BKTR
603 lock_info->locks[i].backtrace = bt;
604#endif
605 lock_info->num_locks++;
606
607 pthread_mutex_unlock(&lock_info->lock);
608}
609
610void ast_mark_lock_acquired(void *lock_addr)
611{
612 struct thr_lock_info *lock_info;
613
614 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
615 return;
616
617 pthread_mutex_lock(&lock_info->lock);
618 if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
619 lock_info->locks[lock_info->num_locks - 1].pending = 0;
620 }
621 pthread_mutex_unlock(&lock_info->lock);
622}
623
624void ast_mark_lock_failed(void *lock_addr)
625{
626 struct thr_lock_info *lock_info;
627
628 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
629 return;
630
631 pthread_mutex_lock(&lock_info->lock);
632 if (lock_info->locks[lock_info->num_locks - 1].lock_addr == lock_addr) {
633 lock_info->locks[lock_info->num_locks - 1].pending = -1;
634 lock_info->locks[lock_info->num_locks - 1].times_locked--;
635 }
636 pthread_mutex_unlock(&lock_info->lock);
637}
638
639int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, int *lineno, char *func, size_t func_size, char *mutex_name, size_t mutex_name_size)
640{
641 struct thr_lock_info *lock_info;
642 int i = 0;
643
644 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
645 return -1;
646
647 pthread_mutex_lock(&lock_info->lock);
648
649 for (i = lock_info->num_locks - 1; i >= 0; i--) {
650 if (lock_info->locks[i].lock_addr == lock_addr)
651 break;
652 }
653
654 if (i == -1) {
655 /* Lock not found :( */
656 pthread_mutex_unlock(&lock_info->lock);
657 return -1;
658 }
659
660 ast_copy_string(filename, lock_info->locks[i].file, filename_size);
661 *lineno = lock_info->locks[i].line_num;
662 ast_copy_string(func, lock_info->locks[i].func, func_size);
663 ast_copy_string(mutex_name, lock_info->locks[i].lock_name, mutex_name_size);
664
665 pthread_mutex_unlock(&lock_info->lock);
666
667 return 0;
668}
669
670#ifdef HAVE_BKTR
671void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
672#else
673void ast_remove_lock_info(void *lock_addr)
674#endif
675{
676 struct thr_lock_info *lock_info;
677 int i = 0;
678
679 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
680 return;
681
682 pthread_mutex_lock(&lock_info->lock);
683
684 for (i = lock_info->num_locks - 1; i >= 0; i--) {
685 if (lock_info->locks[i].lock_addr == lock_addr)
686 break;
687 }
688
689 if (i == -1) {
690 /* Lock not found :( */
691 pthread_mutex_unlock(&lock_info->lock);
692 return;
693 }
694
695 if (lock_info->locks[i].times_locked > 1) {
696 lock_info->locks[i].times_locked--;
697#ifdef HAVE_BKTR
698 lock_info->locks[i].backtrace = bt;
699#endif
700 pthread_mutex_unlock(&lock_info->lock);
701 return;
702 }
703
704 if (i < lock_info->num_locks - 1) {
705 /* Not the last one ... *should* be rare! */
706 memmove(&lock_info->locks[i], &lock_info->locks[i + 1],
707 (lock_info->num_locks - (i + 1)) * sizeof(lock_info->locks[0]));
708 }
709
710 lock_info->num_locks--;
711
712 pthread_mutex_unlock(&lock_info->lock);
713}
714
715static const char *locktype2str(enum ast_lock_type type)
716{
717 switch (type) {
718 case AST_MUTEX:
719 return "MUTEX";
720 case AST_RDLOCK:
721 return "RDLOCK";
722 case AST_WRLOCK:
723 return "WRLOCK";
724 }
725
726 return "UNKNOWN";
727}
728
729#ifdef HAVE_BKTR
730static void append_backtrace_information(struct ast_str **str, struct ast_bt *bt)
731{
732 char **symbols;
733
734 if (!bt) {
735 ast_str_append(str, 0, "\tNo backtrace to print\n");
736 return;
737 }
738
739 if ((symbols = backtrace_symbols(bt->addresses, bt->num_frames))) {
740 int frame_iterator;
741
742 for (frame_iterator = 0; frame_iterator < bt->num_frames; ++frame_iterator) {
743 ast_str_append(str, 0, "\t%s\n", symbols[frame_iterator]);
744 }
745
746 free(symbols);
747 } else {
748 ast_str_append(str, 0, "\tCouldn't retrieve backtrace symbols\n");
749 }
750}
751#endif
752
753static void append_lock_information(struct ast_str **str, struct thr_lock_info *lock_info, int i)
754{
755 int j;
756 ast_mutex_t *lock;
757 struct ast_lock_track *lt;
758
759 ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d)\n",
760 lock_info->locks[i].pending > 0 ? "Waiting for " :
761 lock_info->locks[i].pending < 0 ? "Tried and failed to get " : "", i,
762 lock_info->locks[i].file,
763 locktype2str(lock_info->locks[i].type),
764 lock_info->locks[i].line_num,
765 lock_info->locks[i].func, lock_info->locks[i].lock_name,
766 lock_info->locks[i].lock_addr,
767 lock_info->locks[i].times_locked);
768#ifdef HAVE_BKTR
769 append_backtrace_information(str, lock_info->locks[i].backtrace);
770#endif
771
772 if (!lock_info->locks[i].pending || lock_info->locks[i].pending == -1)
773 return;
774
775 /* We only have further details for mutexes right now */
776 if (lock_info->locks[i].type != AST_MUTEX)
777 return;
778
779 lock = lock_info->locks[i].lock_addr;
780 lt = &lock->track;
781 ast_reentrancy_lock(lt);
782 for (j = 0; *str && j < lt->reentrancy; j++) {
783 ast_str_append(str, 0, "=== --- ---> Locked Here: %s line %d (%s)\n",
784 lt->file[j], lt->lineno[j], lt->func[j]);
785 }
786 ast_reentrancy_unlock(lt);
787}
788
789
790/*! This function can help you find highly temporal locks; locks that happen for a
791 short time, but at unexpected times, usually at times that create a deadlock,
792 Why is this thing locked right then? Who is locking it? Who am I fighting
793 with for this lock?
794
795 To answer such questions, just call this routine before you would normally try
796 to aquire a lock. It doesn't do anything if the lock is not acquired. If the
797 lock is taken, it will publish a line or two to the console via ast_log().
798
799 Sometimes, the lock message is pretty uninformative. For instance, you might
800 find that the lock is being aquired deep within the astobj2 code; this tells
801 you little about higher level routines that call the astobj2 routines.
802 But, using gdb, you can set a break at the ast_log below, and for that
803 breakpoint, you can set the commands:
804 where
805 cont
806 which will give a stack trace and continue. -- that aught to do the job!
807
808*/
809void log_show_lock(void *this_lock_addr)
810{
811 struct thr_lock_info *lock_info;
812 struct ast_str *str;
813
814 if (!(str = ast_str_create(4096))) {
815 ast_log(LOG_NOTICE,"Could not create str\n");
816 return;
817 }
818
819
820 pthread_mutex_lock(&lock_infos_lock.mutex);
821 AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
822 int i;
823 pthread_mutex_lock(&lock_info->lock);
824 for (i = 0; str && i < lock_info->num_locks; i++) {
825 /* ONLY show info about this particular lock, if
826 it's acquired... */
827 if (lock_info->locks[i].lock_addr == this_lock_addr) {
828 append_lock_information(&str, lock_info, i);
829 ast_log(LOG_NOTICE, "%s", ast_str_buffer(str));
830 break;
831 }
832 }
833 pthread_mutex_unlock(&lock_info->lock);
834 }
835 pthread_mutex_unlock(&lock_infos_lock.mutex);
836 ast_free(str);
837}
838
839
840static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
841{
842 struct thr_lock_info *lock_info;
843 struct ast_str *str;
844
845 if (!(str = ast_str_create(4096)))
846 return CLI_FAILURE;
847
848 switch (cmd) {
849 case CLI_INIT:
850 e->command = "core show locks";
851 e->usage =
852 "Usage: core show locks\n"
853 " This command is for lock debugging. It prints out which locks\n"
854 "are owned by each active thread.\n";
855 return NULL;
856
857 case CLI_GENERATE:
858 return NULL;
859 }
860
861 ast_str_append(&str, 0, "\n"
862 "=======================================================================\n"
863 "=== Currently Held Locks ==============================================\n"
864 "=======================================================================\n"
865 "===\n"
866 "=== <pending> <lock#> (<file>): <lock type> <line num> <function> <lock name> <lock addr> (times locked)\n"
867 "===\n");
868
869 if (!str)
870 return CLI_FAILURE;
871
872 pthread_mutex_lock(&lock_infos_lock.mutex);
873 AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
874 int i;
875 if (lock_info->num_locks) {
876 ast_str_append(&str, 0, "=== Thread ID: %ld (%s)\n", (long) lock_info->thread_id,
877 lock_info->thread_name);
878 pthread_mutex_lock(&lock_info->lock);
879 for (i = 0; str && i < lock_info->num_locks; i++) {
880 append_lock_information(&str, lock_info, i);
881 }
882 pthread_mutex_unlock(&lock_info->lock);
883 if (!str)
884 break;
885 ast_str_append(&str, 0, "=== -------------------------------------------------------------------\n"
886 "===\n");
887 if (!str)
888 break;
889 }
890 }
891 pthread_mutex_unlock(&lock_infos_lock.mutex);
892
893 if (!str)
894 return CLI_FAILURE;
895
896 ast_str_append(&str, 0, "=======================================================================\n"
897 "\n");
898
899 if (!str)
900 return CLI_FAILURE;
901
902 ast_cli(a->fd, "%s", ast_str_buffer(str));
903
904 ast_free(str);
905
906 return CLI_SUCCESS;
907}
908
909static struct ast_cli_entry utils_cli[] = {
910 AST_CLI_DEFINE(handle_show_locks, "Show which locks are held by which thread"),
911};
912
913#endif /* DEBUG_THREADS */
914
915/*
916 * support for 'show threads'. The start routine is wrapped by
917 * dummy_start(), so that ast_register_thread() and
918 * ast_unregister_thread() know the thread identifier.
919 */
920struct thr_arg {
921 void *(*start_routine)(void *);
922 void *data;
923 char *name;
924};
925
926/*
927 * on OS/X, pthread_cleanup_push() and pthread_cleanup_pop()
928 * are odd macros which start and end a block, so they _must_ be
929 * used in pairs (the latter with a '1' argument to call the
930 * handler on exit.
931 * On BSD we don't need this, but we keep it for compatibility.
932 */
933static void *dummy_start(void *data)
934{
935 void *ret;
936 struct thr_arg a = *((struct thr_arg *) data); /* make a local copy */
937#ifdef DEBUG_THREADS
938 struct thr_lock_info *lock_info;
939 pthread_mutexattr_t mutex_attr;
940#endif
941
942 /* note that even though data->name is a pointer to allocated memory,
943 we are not freeing it here because ast_register_thread is going to
944 keep a copy of the pointer and then ast_unregister_thread will
945 free the memory
946 */
947 ast_free(data);
948 ast_register_thread(a.name);
949 pthread_cleanup_push(ast_unregister_thread, (void *) pthread_self());
950
951#ifdef DEBUG_THREADS
952 if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
953 return NULL;
954
955 lock_info->thread_id = pthread_self();
956 lock_info->thread_name = strdup(a.name);
957
958 pthread_mutexattr_init(&mutex_attr);
959 pthread_mutexattr_settype(&mutex_attr, AST_MUTEX_KIND);
960 pthread_mutex_init(&lock_info->lock, &mutex_attr);
961 pthread_mutexattr_destroy(&mutex_attr);
962
963 pthread_mutex_lock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
964 AST_LIST_INSERT_TAIL(&lock_infos, lock_info, entry);
965 pthread_mutex_unlock(&lock_infos_lock.mutex); /* Intentionally not the wrapper */
966#endif /* DEBUG_THREADS */
967
968 ret = a.start_routine(a.data);
969
970 pthread_cleanup_pop(1);
971
972 return ret;
973}
974
975#endif /* !LOW_MEMORY */
976
977int ast_pthread_create_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
978 void *data, size_t stacksize, const char *file, const char *caller,
979 int line, const char *start_fn)
980{
981#if !defined(LOW_MEMORY)
982 struct thr_arg *a;
983#endif
984
985 if (!attr) {
986 attr = alloca(sizeof(*attr));
987 pthread_attr_init(attr);
988 }
989
990#ifdef __linux__
991 /* On Linux, pthread_attr_init() defaults to PTHREAD_EXPLICIT_SCHED,
992 which is kind of useless. Change this here to
993 PTHREAD_INHERIT_SCHED; that way the -p option to set realtime
994 priority will propagate down to new threads by default.
995 This does mean that callers cannot set a different priority using
996 PTHREAD_EXPLICIT_SCHED in the attr argument; instead they must set
997 the priority afterwards with pthread_setschedparam(). */
998 if ((errno = pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED)))
999 ast_log(LOG_WARNING, "pthread_attr_setinheritsched: %s\n", strerror(errno));
1000#endif
1001
1002 if (!stacksize)
1003 stacksize = AST_STACKSIZE;
1004
1005 if ((errno = pthread_attr_setstacksize(attr, stacksize ? stacksize : AST_STACKSIZE)))
1006 ast_log(LOG_WARNING, "pthread_attr_setstacksize: %s\n", strerror(errno));
1007
1008#if !defined(LOW_MEMORY)
1009 if ((a = ast_malloc(sizeof(*a)))) {
1010 a->start_routine = start_routine;
1011 a->data = data;
1012 start_routine = dummy_start;
1013 if (asprintf(&a->name, "%-20s started at [%5d] %s %s()",
1014 start_fn, line, file, caller) < 0) {
1015 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
1016 a->name = NULL;
1017 }
1018 data = a;
1019 }
1020#endif /* !LOW_MEMORY */
1021
1022 return pthread_create(thread, attr, start_routine, data); /* We're in ast_pthread_create, so it's okay */
1023}
1024
1025
1026int ast_pthread_create_detached_stack(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *),
1027 void *data, size_t stacksize, const char *file, const char *caller,
1028 int line, const char *start_fn)
1029{
1030 unsigned char attr_destroy = 0;
1031 int res;
1032
1033 if (!attr) {
1034 attr = alloca(sizeof(*attr));
1035 pthread_attr_init(attr);
1036 attr_destroy = 1;
1037 }
1038
1039 if ((errno = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED)))
1040 ast_log(LOG_WARNING, "pthread_attr_setdetachstate: %s\n", strerror(errno));
1041
1042 res = ast_pthread_create_stack(thread, attr, start_routine, data,
1043 stacksize, file, caller, line, start_fn);
1044
1045 if (attr_destroy)
1046 pthread_attr_destroy(attr);
1047
1048 return res;
1049}
1050
1051int ast_wait_for_input(int fd, int ms)
1052{
1053 struct pollfd pfd[1];
1054 memset(pfd, 0, sizeof(pfd));
1055 pfd[0].fd = fd;
1056 pfd[0].events = POLLIN|POLLPRI;
1057 return ast_poll(pfd, 1, ms);
1058}
1059
1060static int ast_wait_for_output(int fd, int timeoutms)
1061{
1062 struct pollfd pfd = {
1063 .fd = fd,
1064 .events = POLLOUT,
1065 };
1066 int res;
1067 struct timeval start = ast_tvnow();
1068 int elapsed = 0;
1069
1070 /* poll() until the fd is writable without blocking */
1071 while ((res = ast_poll(&pfd, 1, timeoutms - elapsed)) <= 0) {
1072 if (res == 0) {
1073 /* timed out. */
1074#ifndef STANDALONE
1075 ast_debug(1, "Timed out trying to write\n");
1076#endif
1077 return -1;
1078 } else if (res == -1) {
1079 /* poll() returned an error, check to see if it was fatal */
1080
1081 if (errno == EINTR || errno == EAGAIN) {
1082 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
1083 if (elapsed >= timeoutms) {
1084 return -1;
1085 }
1086 /* This was an acceptable error, go back into poll() */
1087 continue;
1088 }
1089
1090 /* Fatal error, bail. */
1091 ast_log(LOG_ERROR, "poll returned error: %s\n", strerror(errno));
1092
1093 return -1;
1094 }
1095 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
1096 if (elapsed >= timeoutms) {
1097 return -1;
1098 }
1099 }
1100
1101 return 0;
1102}
1103
1104/*!
1105 * Try to write string, but wait no more than ms milliseconds before timing out.
1106 *
1107 * \note The code assumes that the file descriptor has NONBLOCK set,
1108 * so there is only one system call made to do a write, unless we actually
1109 * have a need to wait. This way, we get better performance.
1110 * If the descriptor is blocking, all assumptions on the guaranteed
1111 * detail do not apply anymore.
1112 */
1113int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
1114{
1115 struct timeval start = ast_tvnow();
1116 int res = 0;
1117 int elapsed = 0;
1118
1119 while (len) {
1120 if (ast_wait_for_output(fd, timeoutms - elapsed)) {
1121 return -1;
1122 }
1123
1124 res = write(fd, s, len);
1125
1126 if (res < 0 && errno != EAGAIN && errno != EINTR) {
1127 /* fatal error from write() */
1128 ast_log(LOG_ERROR, "write() returned error: %s\n", strerror(errno));
1129 return -1;
1130 }
1131
1132 if (res < 0) {
1133 /* It was an acceptable error */
1134 res = 0;
1135 }
1136
1137 /* Update how much data we have left to write */
1138 len -= res;
1139 s += res;
1140 res = 0;
1141
1142 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
1143 if (elapsed >= timeoutms) {
1144 /* We've taken too long to write
1145 * This is only an error condition if we haven't finished writing. */
1146 res = len ? -1 : 0;
1147 break;
1148 }
1149 }
1150
1151 return res;
1152}
1153
1154int ast_careful_fwrite(FILE *f, int fd, const char *src, size_t len, int timeoutms)
1155{
1156 struct timeval start = ast_tvnow();
1157 int n = 0;
1158 int elapsed = 0;
1159
1160 while (len) {
1161 if (ast_wait_for_output(fd, timeoutms - elapsed)) {
1162 /* poll returned a fatal error, so bail out immediately. */
1163 return -1;
1164 }
1165
1166 /* Clear any errors from a previous write */
1167 clearerr(f);
1168
1169 n = fwrite(src, 1, len, f);
1170
1171 if (ferror(f) && errno != EINTR && errno != EAGAIN) {
1172 /* fatal error from fwrite() */
1173 if (!feof(f)) {
1174 /* Don't spam the logs if it was just that the connection is closed. */
1175 ast_log(LOG_ERROR, "fwrite() returned error: %s\n", strerror(errno));
1176 }
1177 n = -1;
1178 break;
1179 }
1180
1181 /* Update for data already written to the socket */
1182 len -= n;
1183 src += n;
1184
1185 elapsed = ast_tvdiff_ms(ast_tvnow(), start);
1186 if (elapsed >= timeoutms) {
1187 /* We've taken too long to write
1188 * This is only an error condition if we haven't finished writing. */
1189 n = len ? -1 : 0;
1190 break;
1191 }
1192 }
1193
1194 while (fflush(f)) {
1195 if (errno == EAGAIN || errno == EINTR) {
1196 continue;
1197 }
1198 if (!feof(f)) {
1199 /* Don't spam the logs if it was just that the connection is closed. */
1200 ast_log(LOG_ERROR, "fflush() returned error: %s\n", strerror(errno));
1201 }
1202 n = -1;
1203 break;
1204 }
1205
1206 return n < 0 ? -1 : 0;
1207}
1208
1209char *ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
1210{
1211 char *e;
1212 char *q;
1213
1214 s = ast_strip(s);
1215 if ((q = strchr(beg_quotes, *s)) && *q != '\0') {
1216 e = s + strlen(s) - 1;
1217 if (*e == *(end_quotes + (q - beg_quotes))) {
1218 s++;
1219 *e = '\0';
1220 }
1221 }
1222
1223 return s;
1224}
1225
1226char *ast_unescape_semicolon(char *s)
1227{
1228 char *e;
1229 char *work = s;
1230
1231 while ((e = strchr(work, ';'))) {
1232 if ((e > work) && (*(e-1) == '\\')) {
1233 memmove(e - 1, e, strlen(e) + 1);
1234 work = e;
1235 } else {
1236 work = e + 1;
1237 }
1238 }
1239
1240 return s;
1241}
1242
1243/* !\brief unescape some C sequences in place, return pointer to the original string.
1244 */
1245char *ast_unescape_c(char *src)
1246{
1247 char c, *ret, *dst;
1248
1249 if (src == NULL)
1250 return NULL;
1251 for (ret = dst = src; (c = *src++); *dst++ = c ) {
1252 if (c != '\\')
1253 continue; /* copy char at the end of the loop */
1254 switch ((c = *src++)) {
1255 case '\0': /* special, trailing '\' */
1256 c = '\\';
1257 break;
1258 case 'b': /* backspace */
1259 c = '\b';
1260 break;
1261 case 'f': /* form feed */
1262 c = '\f';
1263 break;
1264 case 'n':
1265 c = '\n';
1266 break;
1267 case 'r':
1268 c = '\r';
1269 break;
1270 case 't':
1271 c = '\t';
1272 break;
1273 }
1274 /* default, use the char literally */
1275 }
1276 *dst = '\0';
1277 return ret;
1278}
1279
1280int ast_build_string_va(char **buffer, size_t *space, const char *fmt, va_list ap)
1281{
1282 int result;
1283
1284 if (!buffer || !*buffer || !space || !*space)
1285 return -1;
1286
1287 result = vsnprintf(*buffer, *space, fmt, ap);
1288
1289 if (result < 0)
1290 return -1;
1291 else if (result > *space)
1292 result = *space;
1293
1294 *buffer += result;
1295 *space -= result;
1296 return 0;
1297}
1298
1299int ast_build_string(char **buffer, size_t *space, const char *fmt, ...)
1300{
1301 va_list ap;
1302 int result;
1303
1304 va_start(ap, fmt);
1305 result = ast_build_string_va(buffer, space, fmt, ap);
1306 va_end(ap);
1307
1308 return result;
1309}
1310
1311int ast_true(const char *s)
1312{
1313 if (ast_strlen_zero(s))
1314 return 0;
1315
1316 /* Determine if this is a true value */
1317 if (!strcasecmp(s, "yes") ||
1318 !strcasecmp(s, "true") ||
1319 !strcasecmp(s, "y") ||
1320 !strcasecmp(s, "t") ||
1321 !strcasecmp(s, "1") ||
1322 !strcasecmp(s, "on"))
1323 return -1;
1324
1325 return 0;
1326}
1327
1328int ast_false(const char *s)
1329{
1330 if (ast_strlen_zero(s))
1331 return 0;
1332
1333 /* Determine if this is a false value */
1334 if (!strcasecmp(s, "no") ||
1335 !strcasecmp(s, "false") ||
1336 !strcasecmp(s, "n") ||
1337 !strcasecmp(s, "f") ||
1338 !strcasecmp(s, "0") ||
1339 !strcasecmp(s, "off"))
1340 return -1;
1341
1342 return 0;
1343}
1344
1345#define ONE_MILLION 1000000
1346/*
1347 * put timeval in a valid range. usec is 0..999999
1348 * negative values are not allowed and truncated.
1349 */
1350static struct timeval tvfix(struct timeval a)
1351{
1352 if (a.tv_usec >= ONE_MILLION) {
1353 ast_log(LOG_WARNING, "warning too large timestamp %ld.%ld\n",
1354 (long)a.tv_sec, (long int) a.tv_usec);
1355 a.tv_sec += a.tv_usec / ONE_MILLION;
1356 a.tv_usec %= ONE_MILLION;
1357 } else if (a.tv_usec < 0) {
1358 ast_log(LOG_WARNING, "warning negative timestamp %ld.%ld\n",
1359 (long)a.tv_sec, (long int) a.tv_usec);
1360 a.tv_usec = 0;
1361 }
1362 return a;
1363}
1364
1365struct timeval ast_tvadd(struct timeval a, struct timeval b)
1366{
1367 /* consistency checks to guarantee usec in 0..999999 */
1368 a = tvfix(a);
1369 b = tvfix(b);
1370 a.tv_sec += b.tv_sec;
1371 a.tv_usec += b.tv_usec;
1372 if (a.tv_usec >= ONE_MILLION) {
1373 a.tv_sec++;
1374 a.tv_usec -= ONE_MILLION;
1375 }
1376 return a;
1377}
1378
1379struct timeval ast_tvsub(struct timeval a, struct timeval b)
1380{
1381 /* consistency checks to guarantee usec in 0..999999 */
1382 a = tvfix(a);
1383 b = tvfix(b);
1384 a.tv_sec -= b.tv_sec;
1385 a.tv_usec -= b.tv_usec;
1386 if (a.tv_usec < 0) {
1387 a.tv_sec-- ;
1388 a.tv_usec += ONE_MILLION;
1389 }
1390 return a;
1391}
1392#undef ONE_MILLION
1393
1394/*! \brief glibc puts a lock inside random(3), so that the results are thread-safe.
1395 * BSD libc (and others) do not. */
1396
1397#ifndef linux
1398AST_MUTEX_DEFINE_STATIC(randomlock);
1399#endif
1400
1401long int ast_random(void)
1402{
1403 long int res;
1404#ifdef HAVE_DEV_URANDOM
1405 if (dev_urandom_fd >= 0) {
1406 int read_res = read(dev_urandom_fd, &res, sizeof(res));
1407 if (read_res > 0) {
1408 long int rm = RAND_MAX;
1409 res = res < 0 ? ~res : res;
1410 rm++;
1411 return res % rm;
1412 }
1413 }
1414#endif
1415#ifdef linux
1416 res = random();
1417#else
1418 ast_mutex_lock(&randomlock);
1419 res = random();
1420 ast_mutex_unlock(&randomlock);
1421#endif
1422 return res;
1423}
1424
1425char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
1426{
1427 char *dataPut = start;
1428 int inEscape = 0;
1429 int inQuotes = 0;
1430
1431 for (; *start; start++) {
1432 if (inEscape) {
1433 *dataPut++ = *start; /* Always goes verbatim */
1434 inEscape = 0;
1435 } else {
1436 if (*start == '\\') {
1437 inEscape = 1; /* Do not copy \ into the data */
1438 } else if (*start == '\'') {
1439 inQuotes = 1 - inQuotes; /* Do not copy ' into the data */
1440 } else {
1441 /* Replace , with |, unless in quotes */
1442 *dataPut++ = inQuotes ? *start : ((*start == find) ? replace_with : *start);
1443 }
1444 }
1445 }
1446 if (start != dataPut)
1447 *dataPut = 0;
1448 return dataPut;
1449}
1450
1451void ast_join(char *s, size_t len, char * const w[])
1452{
1453 int x, ofs = 0;
1454 const char *src;
1455
1456 /* Join words into a string */
1457 if (!s)
1458 return;
1459 for (x = 0; ofs < len && w[x]; x++) {
1460 if (x > 0)
1461 s[ofs++] = ' ';
1462 for (src = w[x]; *src && ofs < len; src++)
1463 s[ofs++] = *src;
1464 }
1465 if (ofs == len)
1466 ofs--;
1467 s[ofs] = '\0';
1468}
1469
1470/*
1471 * stringfields support routines.
1472 */
1473
1474const char __ast_string_field_empty[] = ""; /*!< the empty string */
1475
1476/*! \brief add a new block to the pool.
1477 * We can only allocate from the topmost pool, so the
1478 * fields in *mgr reflect the size of that only.
1479 */
1480static int add_string_pool(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
1481 size_t size, const char *file, int lineno, const char *func)
1482{
1483 struct ast_string_field_pool *pool;
1484
1485#if defined(__AST_DEBUG_MALLOC)
1486 if (!(pool = __ast_calloc(1, sizeof(*pool) + size, file, lineno, func))) {
1487 return -1;
1488 }
1489#else
1490 if (!(pool = ast_calloc(1, sizeof(*pool) + size))) {
1491 return -1;
1492 }
1493#endif
1494
1495 pool->prev = *pool_head;
1496 *pool_head = pool;
1497 mgr->size = size;
1498 mgr->used = 0;
1499 mgr->last_alloc = NULL;
1500
1501 return 0;
1502}
1503
1504/*
1505 * This is an internal API, code should not use it directly.
1506 * It initializes all fields as empty, then uses 'size' for 3 functions:
1507 * size > 0 means initialize the pool list with a pool of given size.
1508 * This must be called right after allocating the object.
1509 * size = 0 means release all pools except the most recent one.
1510 * This is useful to e.g. reset an object to the initial value.
1511 * size < 0 means release all pools.
1512 * This must be done before destroying the object.
1513 */
1514int __ast_string_field_init(struct ast_string_field_mgr *mgr, struct ast_string_field_pool **pool_head,
1515 int needed, const char *file, int lineno, const char *func)
1516{
1517 const char **p = (const char **) pool_head + 1;
1518 struct ast_string_field_pool *cur = NULL;
1519 struct ast_string_field_pool *preserve = NULL;
1520
1521 /* clear fields - this is always necessary */
1522 while ((struct ast_string_field_mgr *) p != mgr)
1523 *p++ = __ast_string_field_empty;
1524 mgr->last_alloc = NULL;
1525#if defined(__AST_DEBUG_MALLOC)
1526 mgr->owner_file = file;
1527 mgr->owner_func = func;
1528 mgr->owner_line = lineno;
1529#endif
1530 if (needed > 0) { /* allocate the initial pool */
1531 *pool_head = NULL;
1532 return add_string_pool(mgr, pool_head, needed, file, lineno, func);
1533 }
1534 if (needed < 0) { /* reset all pools */
1535 if (*pool_head == NULL) {
1536 ast_log(LOG_WARNING, "trying to reset empty pool\n");
1537 return -1;
1538 }
1539 cur = *pool_head;
1540 } else { /* preserve the last pool */
1541 if (*pool_head == NULL) {
1542 ast_log(LOG_WARNING, "trying to reset empty pool\n");
1543 return -1;
1544 }
1545 mgr->used = 0;
1546 preserve = *pool_head;
1547 cur = preserve->prev;
1548 }
1549
1550 if (preserve) {
1551 preserve->prev = NULL;
1552 }
1553
1554 while (cur) {
1555 struct ast_string_field_pool *prev = cur->prev;
1556
1557 if (cur != preserve) {
1558 ast_free(cur);
1559 }
1560 cur = prev;
1561 }
1562
1563 *pool_head = preserve;
1564
1565 return 0;
1566}
1567
1568ast_string_field __ast_string_field_alloc_space(struct ast_string_field_mgr *mgr,
1569 struct ast_string_field_pool **pool_head, size_t needed)
1570{
1571 char *result = NULL;
1572 size_t space = mgr->size - mgr->used;
1573
1574 if (__builtin_expect(needed > space, 0)) {
1575 size_t new_size = mgr->size * 2;
1576
1577 while (new_size < needed)
1578 new_size *= 2;
1579
1580#if defined(__AST_DEBUG_MALLOC)
1581 if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
1582 return NULL;
1583#else
1584 if (add_string_pool(mgr, pool_head, new_size, __FILE__, __LINE__, __FUNCTION__))
1585 return NULL;
1586#endif
1587 }
1588
1589 result = (*pool_head)->base + mgr->used;
1590 mgr->used += needed;
1591 mgr->last_alloc = result;
1592 return result;
1593}
1594
1595int __ast_string_field_ptr_grow(struct ast_string_field_mgr *mgr, size_t needed,
1596 const ast_string_field *ptr)
1597{
1598 int grow = needed - (strlen(*ptr) + 1);
1599 size_t space = mgr->size - mgr->used;
1600
1601 if (grow <= 0) {
1602 return 0;
1603 }
1604
1605 if (*ptr != mgr->last_alloc) {
1606 return 1;
1607 }
1608
1609 if (space < grow) {
1610 return 1;
1611 }
1612
1613 mgr->used += grow;
1614
1615 return 0;
1616}
1617
1618void __ast_string_field_ptr_build_va(struct ast_string_field_mgr *mgr,
1619 struct ast_string_field_pool **pool_head,
1620 ast_string_field *ptr, const char *format, va_list ap1, va_list ap2)
1621{
1622 size_t needed;
1623 size_t available;
1624 size_t space = mgr->size - mgr->used;
1625 char *target;
1626
1627 /* if the field already has space allocated, try to reuse it;
1628 otherwise, use the empty space at the end of the current
1629 pool
1630 */
1631 if ((*ptr)[0] != '\0') {
1632 target = (char *) *ptr;
1633 available = strlen(target) + 1;
1634 } else {
1635 target = (*pool_head)->base + mgr->used;
1636 available = space;
1637 }
1638
1639 needed = vsnprintf(target, available, format, ap1) + 1;
1640
1641 va_end(ap1);
1642
1643 if (needed > available) {
1644 /* if the space needed can be satisfied by using the current
1645 pool (which could only occur if we tried to use the field's
1646 allocated space and failed), then use that space; otherwise
1647 allocate a new pool
1648 */
1649 if (needed > space) {
1650 size_t new_size = mgr->size * 2;
1651
1652 while (new_size < needed)
1653 new_size *= 2;
1654
1655#if defined(__AST_DEBUG_MALLOC)
1656 if (add_string_pool(mgr, pool_head, new_size, mgr->owner_file, mgr->owner_line, mgr->owner_func))
1657 return;
1658#else
1659 if (add_string_pool(mgr, pool_head, new_size, NULL, 0, NULL))
1660 return;
1661#endif
1662 }
1663
1664 target = (*pool_head)->base + mgr->used;
1665 vsprintf(target, format, ap2);
1666 }
1667
1668 if (*ptr != target) {
1669 mgr->last_alloc = *ptr = target;
1670 mgr->used += needed;
1671 }
1672}
1673
1674void __ast_string_field_ptr_build(struct ast_string_field_mgr *mgr,
1675 struct ast_string_field_pool **pool_head,
1676 ast_string_field *ptr, const char *format, ...)
1677{
1678 va_list ap1, ap2;
1679
1680 va_start(ap1, format);
1681 va_start(ap2, format); /* va_copy does not exist on FreeBSD */
1682
1683 __ast_string_field_ptr_build_va(mgr, pool_head, ptr, format, ap1, ap2);
1684
1685 va_end(ap1);
1686 va_end(ap2);
1687}
1688/* end of stringfields support */
1689
1690AST_MUTEX_DEFINE_STATIC(fetchadd_m); /* used for all fetc&add ops */
1691
1692int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
1693{
1694 int ret;
1695 ast_mutex_lock(&fetchadd_m);
1696 ret = *p;
1697 *p += v;
1698 ast_mutex_unlock(&fetchadd_m);
1699 return ret;
1700}
1701
1702/*! \brief
1703 * get values from config variables.
1704 */
1705int ast_get_timeval(const char *src, struct timeval *dst, struct timeval _default, int *consumed)
1706{
1707 long double dtv = 0.0;
1708 int scanned;
1709
1710 if (dst == NULL)
1711 return -1;
1712
1713 *dst = _default;
1714
1715 if (ast_strlen_zero(src))
1716 return -1;
1717
1718 /* only integer at the moment, but one day we could accept more formats */
1719 if (sscanf(src, "%30Lf%n", &dtv, &scanned) > 0) {
1720 dst->tv_sec = dtv;
1721 dst->tv_usec = (dtv - dst->tv_sec) * 1000000.0;
1722 if (consumed)
1723 *consumed = scanned;
1724 return 0;
1725 } else
1726 return -1;
1727}
1728
1729/*! \brief
1730 * get values from config variables.
1731 */
1732int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
1733{
1734 long t;
1735 int scanned;
1736
1737 if (dst == NULL)
1738 return -1;
1739
1740 *dst = _default;
1741
1742 if (ast_strlen_zero(src))
1743 return -1;
1744
1745 /* only integer at the moment, but one day we could accept more formats */
1746 if (sscanf(src, "%30ld%n", &t, &scanned) == 1) {
1747 *dst = t;
1748 if (consumed)
1749 *consumed = scanned;
1750 return 0;
1751 } else
1752 return -1;
1753}
1754
1755void ast_enable_packet_fragmentation(int sock)
1756{
1757#if defined(HAVE_IP_MTU_DISCOVER)
1758 int val = IP_PMTUDISC_DONT;
1759
1760 if (setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)))
1761 ast_log(LOG_WARNING, "Unable to disable PMTU discovery. Large UDP packets may fail to be delivered when sent from this socket.\n");
1762#endif /* HAVE_IP_MTU_DISCOVER */
1763}
1764
1765int ast_mkdir(const char *path, int mode)
1766{
1767 char *ptr;
1768 int len = strlen(path), count = 0, x, piececount = 0;
1769 char *tmp = ast_strdupa(path);
1770 char **pieces;
1771 char *fullpath = alloca(len + 1);
1772 int res = 0;
1773
1774 for (ptr = tmp; *ptr; ptr++) {
1775 if (*ptr == '/')
1776 count++;
1777 }
1778
1779 /* Count the components to the directory path */
1780 pieces = alloca(count * sizeof(*pieces));
1781 for (ptr = tmp; *ptr; ptr++) {
1782 if (*ptr == '/') {
1783 *ptr = '\0';
1784 pieces[piececount++] = ptr + 1;
1785 }
1786 }
1787
1788 *fullpath = '\0';
1789 for (x = 0; x < piececount; x++) {
1790 /* This looks funky, but the buffer is always ideally-sized, so it's fine. */
1791 strcat(fullpath, "/");
1792 strcat(fullpath, pieces[x]);
1793 res = mkdir(fullpath, mode);
1794 if (res && errno != EEXIST)
1795 return errno;
1796 }
1797 return 0;
1798}
1799
1800int ast_utils_init(void)
1801{
1802#ifdef HAVE_DEV_URANDOM
1803 dev_urandom_fd = open("/dev/urandom", O_RDONLY);
1804#endif
1805 base64_init();
1806#ifdef DEBUG_THREADS
1807#if !defined(LOW_MEMORY)
1808 ast_cli_register_multiple(utils_cli, ARRAY_LEN(utils_cli));
1809#endif
1810#endif
1811 return 0;
1812}
1813
1814#ifndef __AST_DEBUG_MALLOC
1815int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...)
1816{
1817 int res;
1818 va_list ap;
1819
1820 va_start(ap, fmt);
1821 if ((res = vasprintf(ret, fmt, ap)) == -1) {
1822 MALLOC_FAILURE_MSG;
1823 }
1824 va_end(ap);
1825
1826 return res;
1827}
1828#endif
01829
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2010-12-06 16:56:12 +0000
+++ .pc/applied-patches 2011-01-20 23:58:58 +0000
@@ -13,3 +13,4 @@
13sound_files13sound_files
14dnsmgr-A-SRV-handling14dnsmgr-A-SRV-handling
15unattended_fix15unattended_fix
16AST-2011-001-1.6.2
1617
=== modified file 'debian/changelog'
--- debian/changelog 2010-12-06 16:56:12 +0000
+++ debian/changelog 2011-01-20 23:58:58 +0000
@@ -1,3 +1,13 @@
1asterisk (1:1.6.2.5-0ubuntu1.3) lucid-security; urgency=low
2
3 * SECURITY UPDATE: Stack buffer overflow in SIP channel driver. (LP: #705014)
4 - debian/patches/AST-2011-001-1.6.2: The size of the output buffer passed
5 to the ast_uri_encode function is now properly respected in main/utils.c.
6 Patch courtesy of upstream.
7 - CVE-2011-0495
8
9 -- Dave Walker (Daviey) <DaveWalker@ubuntu.com> Thu, 20 Jan 2011 23:31:55 +0000
10
1asterisk (1:1.6.2.5-0ubuntu1.2) lucid-proposed; urgency=low11asterisk (1:1.6.2.5-0ubuntu1.2) lucid-proposed; urgency=low
212
3 * debian/patches/unattended_fix: Fix attended transfer call in 1.2.6.513 * debian/patches/unattended_fix: Fix attended transfer call in 1.2.6.5
414
=== added file 'debian/patches/AST-2011-001-1.6.2'
--- debian/patches/AST-2011-001-1.6.2 1970-01-01 00:00:00 +0000
+++ debian/patches/AST-2011-001-1.6.2 2011-01-20 23:58:58 +0000
@@ -0,0 +1,52 @@
1Description: Stack buffer overflow in SIP channel driver.
2 Prevent buffer overflows in ast_uri_encode()
3Origin: upstream, http://downloads.asterisk.org/pub/security/AST-2011-001.html
4Bug-Ubuntu: https://launchpad.net/bugs/705014
5Bug-Debian: http://bugs.debian.org/610487
6Applied-Upstream: http://svnview.digium.com/svn/asterisk?view=revision&revision=301307
7Last-Update: 2011-01-20
8
9--- a/main/utils.c
10+++ b/main/utils.c
11@@ -385,28 +385,27 @@
12 char *reserved = ";/?:@&=+$,# "; /* Reserved chars */
13
14 const char *ptr = string; /* Start with the string */
15- char *out = NULL;
16- char *buf = NULL;
17+ char *out = outbuf;
18
19- ast_copy_string(outbuf, string, buflen);
20-
21- /* If there's no characters to convert, just go through and don't do anything */
22- while (*ptr) {
23+ /* If there's no characters to convert, just go through and copy the string */
24+ while (*ptr && out - outbuf < buflen - 1) {
25 if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) {
26- /* Oops, we need to start working here */
27- if (!buf) {
28- buf = outbuf;
29- out = buf + (ptr - string) ; /* Set output ptr */
30+ if (out - outbuf >= buflen - 3) {
31+ break;
32 }
33+
34 out += sprintf(out, "%%%02x", (unsigned char) *ptr);
35- } else if (buf) {
36- *out = *ptr; /* Continue copying the string */
37+ } else {
38+ *out = *ptr; /* copy the character */
39 out++;
40- }
41+ }
42 ptr++;
43 }
44- if (buf)
45+
46+ if (buflen) {
47 *out = '\0';
48+ }
49+
50 return outbuf;
51 }
52
053
=== modified file 'debian/patches/series'
--- debian/patches/series 2010-12-06 16:56:12 +0000
+++ debian/patches/series 2011-01-20 23:58:58 +0000
@@ -19,3 +19,4 @@
19sound_files19sound_files
20dnsmgr-A-SRV-handling20dnsmgr-A-SRV-handling
21unattended_fix21unattended_fix
22AST-2011-001-1.6.2
2223
=== modified file 'main/utils.c'
--- main/utils.c 2010-02-16 14:08:54 +0000
+++ main/utils.c 2011-01-20 23:58:58 +0000
@@ -385,28 +385,27 @@
385 char *reserved = ";/?:@&=+$,# "; /* Reserved chars */385 char *reserved = ";/?:@&=+$,# "; /* Reserved chars */
386386
387 const char *ptr = string; /* Start with the string */387 const char *ptr = string; /* Start with the string */
388 char *out = NULL;388 char *out = outbuf;
389 char *buf = NULL;389
390390 /* If there's no characters to convert, just go through and copy the string */
391 ast_copy_string(outbuf, string, buflen);391 while (*ptr && out - outbuf < buflen - 1) {
392
393 /* If there's no characters to convert, just go through and don't do anything */
394 while (*ptr) {
395 if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) {392 if ((*ptr < 32) || (doreserved && strchr(reserved, *ptr))) {
396 /* Oops, we need to start working here */393 if (out - outbuf >= buflen - 3) {
397 if (!buf) {394 break;
398 buf = outbuf;
399 out = buf + (ptr - string) ; /* Set output ptr */
400 }395 }
396
401 out += sprintf(out, "%%%02x", (unsigned char) *ptr);397 out += sprintf(out, "%%%02x", (unsigned char) *ptr);
402 } else if (buf) {398 } else {
403 *out = *ptr; /* Continue copying the string */399 *out = *ptr; /* copy the character */
404 out++;400 out++;
405 } 401 }
406 ptr++;402 ptr++;
407 }403 }
408 if (buf)404
405 if (buflen) {
409 *out = '\0';406 *out = '\0';
407 }
408
410 return outbuf;409 return outbuf;
411}410}
412411

Subscribers

People subscribed via source and target branches

to all changes: