Index: utils.c =================================================================== RCS file: /usr/cvsroot/asterisk/utils.c,v retrieving revision 1.61 diff -u -r1.61 utils.c --- utils.c 20 Jul 2005 00:13:14 -0000 1.61 +++ utils.c 30 Jul 2005 12:53:17 -0000 @@ -382,6 +382,62 @@ #endif } +/*--- url_encode: Turn text string to URI-encoded %XX version ---*/ +/* At this point, we're converting from ISO-8859-x (8-bit), not UTF8 + as in the SIP protocol spec + If doreserved == 1 we will convert reserved characters also. + RFC 2396, section 2.4 + outbuf needs to have more memory allocated than the instring + to have room for the expansion. Every char that is converted + is replaced by three ASCII characters. +*/ +char *url_encode(char *string, char *outbuf, int buflen, int doreserved) +{ + char *reserved = ";/?:@&=+$, "; /* Reserved chars */ + + char *ptr = string; /* Start with the string */ + char *out = NULL; + char *buf = NULL; + + strncpy(outbuf, string, buflen); + + /* If there's no characters to convert, just go through and don't do anything */ + while (*ptr) { + if (((unsigned char) *ptr) > 127 || (doreserved && strchr(reserved, *ptr)) ) { + /* Oops, we need to start working here */ + if (!buf) { + buf = outbuf; + out = buf + (ptr - string) ; /* Set output ptr */ + } + out += sprintf(out, "%%%02x", (unsigned char) *ptr); + } else if (buf) { + *out = *ptr; /* Continue copying the string */ + out++; + } + ptr++; + } + if (buf) + *out = '\0'; + return outbuf; +} + +/*--- url_decode: Decode SIP URL (overwrite the string) ---*/ +void url_decode(char *s) +{ + char *o; + unsigned int tmp; + + for (o = s; *s; s++, o++) { + if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) { + /* have '%', two chars and correct parsing */ + *o = tmp; + s += 2; /* Will be incremented once more when we break out */ + } else /* all other cases, just copy */ + *o = *s; + } + *o = '\0'; +} + /* Recursive thread safe replacement of inet_ntoa */ const char *ast_inet_ntoa(char *buf, int bufsiz, struct in_addr ia) { @@ -635,9 +691,9 @@ #ifndef HAVE_STRTOQ #define LONG_MIN (-9223372036854775807L-1L) - /* min value of a "long int" */ + /* min value of a "long int" */ #define LONG_MAX 9223372036854775807L - /* max value of a "long int" */ + /* max value of a "long int" */ /* * Convert a string to a quad integer. @@ -647,85 +703,85 @@ */ uint64_t strtoq(const char *nptr, char **endptr, int base) { - const char *s; - uint64_t acc; - unsigned char c; - uint64_t qbase, cutoff; - int neg, any, cutlim; - - /* - * Skip white space and pick up leading +/- sign if any. - * If base is 0, allow 0x for hex and 0 for octal, else - * assume decimal; if base is already 16, allow 0x. - */ - s = nptr; - do { - c = *s++; - } while (isspace(c)); - if (c == '-') { - neg = 1; - c = *s++; - } else { - neg = 0; - if (c == '+') - c = *s++; - } - if ((base == 0 || base == 16) && - c == '\0' && (*s == 'x' || *s == 'X')) { - c = s[1]; - s += 2; - base = 16; - } - if (base == 0) - base = c == '\0' ? 8 : 10; - - /* - * Compute the cutoff value between legal numbers and illegal - * numbers. That is the largest legal value, divided by the - * base. An input number that is greater than this value, if - * followed by a legal input character, is too big. One that - * is equal to this value may be valid or not; the limit - * between valid and invalid numbers is then based on the last - * digit. For instance, if the range for quads is - * [-9223372036854775808..9223372036854775807] and the input base - * is 10, cutoff will be set to 922337203685477580 and cutlim to - * either 7 (neg==0) or 8 (neg==1), meaning that if we have - * accumulated a value > 922337203685477580, or equal but the - * next digit is > 7 (or 8), the number is too big, and we will - * return a range error. - * - * Set any if any `digits' consumed; make it negative to indicate - * overflow. - */ - qbase = (unsigned)base; - cutoff = neg ? (uint64_t)-(LONG_MIN + LONG_MAX) + LONG_MAX : LONG_MAX; - cutlim = cutoff % qbase; - cutoff /= qbase; - for (acc = 0, any = 0;; c = *s++) { - if (!isascii(c)) - break; - if (isdigit(c)) - c -= '\0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - if (c >= base) - break; - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else { - any = 1; - acc *= qbase; - acc += c; - } - } - if (any < 0) { - acc = neg ? LONG_MIN : LONG_MAX; - } else if (neg) - acc = -acc; - if (endptr != 0) - *((const char **)endptr) = any ? s - 1 : nptr; - return (acc); + const char *s; + uint64_t acc; + unsigned char c; + uint64_t qbase, cutoff; + int neg, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + s = nptr; + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '\0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '\0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for quads is + * [-9223372036854775808..9223372036854775807] and the input base + * is 10, cutoff will be set to 922337203685477580 and cutlim to + * either 7 (neg==0) or 8 (neg==1), meaning that if we have + * accumulated a value > 922337203685477580, or equal but the + * next digit is > 7 (or 8), the number is too big, and we will + * return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + qbase = (unsigned)base; + cutoff = neg ? (uint64_t)-(LONG_MIN + LONG_MAX) + LONG_MAX : LONG_MAX; + cutlim = cutoff % qbase; + cutoff /= qbase; + for (acc = 0, any = 0;; c = *s++) { + if (!isascii(c)) + break; + if (isdigit(c)) + c -= '\0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= qbase; + acc += c; + } + } + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; + } else if (neg) + acc = -acc; + if (endptr != 0) + *((const char **)endptr) = any ? s - 1 : nptr; + return acc; } #endif Index: include/asterisk/utils.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/utils.h,v retrieving revision 1.40 diff -u -r1.40 utils.h --- include/asterisk/utils.h 19 Jul 2005 23:17:02 -0000 1.40 +++ include/asterisk/utils.h 30 Jul 2005 12:53:17 -0000 @@ -128,10 +128,36 @@ }; extern struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp); -/* ast_md5_hash: Produces MD5 hash based on input string */ + +/* ast_md5_hash + \brief Produces MD5 hash based on input string */ extern void ast_md5_hash(char *output, char *input); + extern int ast_base64encode(char *dst, unsigned char *src, int srclen, int max); extern int ast_base64decode(unsigned char *dst, char *src, int max); + +/*! url_encode + \brief Turn text string to URI-encoded %XX version + At this point, we're converting from ISO-8859-x (8-bit), not UTF8 + as in the SIP protocol spec + If doreserved == 1 we will convert reserved characters also. + RFC 2396, section 2.4 + outbuf needs to have more memory allocated than the instring + to have room for the expansion. Every char that is converted + is replaced by three ASCII characters. + \param string String to be converted + \param outbuf Resulting encoded string + \param buflen Size of output buffer + \param doreserved Convert reserved characters +*/ + +char *url_encode(char *string, char *outbuf, int buflen, int doreserved); + +/*! \brief Decode URL (overwrite string) + \param s String to be decoded + */ +void url_decode(char *s); + extern int test_for_thread_safety(void); Index: channels/chan_sip.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v retrieving revision 1.797 diff -u -r1.797 chan_sip.c --- channels/chan_sip.c 28 Jul 2005 18:24:04 -0000 1.797 +++ channels/chan_sip.c 30 Jul 2005 12:53:19 -0000 @@ -1328,23 +1328,6 @@ return res; } -/*--- url_decode: Decode SIP URL (overwrite the string) ---*/ -static void url_decode(char *s) -{ - char *o; - unsigned int tmp; - - for (o = s; *s; s++, o++) { - if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) { - /* have '%', two chars and correct parsing */ - *o = tmp; - s += 2; /* Will be incremented once more when we break out */ - } else /* all other cases, just copy */ - *o = *s; - } - *o = '\0'; -} - /*--- get_in_brackets: Pick out text in brackets from character string ---*/ /* returns pointer to terminated stripped string. modifies input string. */ static char *get_in_brackets(char *tmp) @@ -4270,15 +4253,16 @@ snprintf(p->our_contact, sizeof(p->our_contact), "", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip)); } -/*--- initreqprep: Initiate SIP request to peer/user ---*/ +/*--- initreqprep: Initiate new SIP request to peer/user ---*/ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, char *vxml_url) { - char invite[256]=""; + char invite[256] = ""; char from[256]; char to[256]; - char tmp[80]; + char tmp[BUFSIZ/2]; + char tmp2[BUFSIZ/2]; char iabuf[INET_ADDRSTRLEN]; - char *l = default_callerid, *n=NULL; + char *l = default_callerid, *n = NULL; int x; char urioptions[256]=""; @@ -4294,7 +4278,7 @@ if (p->username && p->username[0] == '+') x=1; - for (; xusername); x++) { + for (; x < strlen(p->username); x++) { if (!strchr(AST_DIGIT_ANYNUM, p->username[x])) { onlydigits = 0; break; @@ -4334,8 +4318,15 @@ else /* Save for any further attempts */ ast_copy_string(p->fromname, n, sizeof(p->fromname)); + if (pedanticsipchecking) { + url_encode(n, tmp, sizeof(tmp), 0); + n = tmp; + url_encode(l, tmp2, sizeof(tmp2), 0); + l = tmp2; + } + if ((ourport != 5060) && ast_strlen_zero(p->fromdomain)) /* Needs to be 5060 */ - snprintf(from, sizeof(from), "\"%s\" ;tag=as%08x", n, l, ast_strlen_zero(p->fromdomain) ? ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip) : p->fromdomain, ourport, p->tag); + snprintf(from, sizeof(from), "\"%s\" ;tag=as%08x", tmp, l, ast_strlen_zero(p->fromdomain) ? ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip) : p->fromdomain, ourport, p->tag); else snprintf(from, sizeof(from), "\"%s\" ;tag=as%08x", n, l, ast_strlen_zero(p->fromdomain) ? ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip) : p->fromdomain, p->tag); @@ -4345,10 +4336,15 @@ ast_copy_string(invite, p->fullcontact, sizeof(invite)); /* Otherwise, use the username while waiting for registration */ } else if (!ast_strlen_zero(p->username)) { + n = p->username; + if (pedanticsipchecking) { + url_encode(n, tmp, sizeof(tmp), 0); + n = tmp; + } if (ntohs(p->sa.sin_port) != 5060) { /* Needs to be 5060 */ - snprintf(invite, sizeof(invite), "sip:%s@%s:%d%s",p->username, p->tohost, ntohs(p->sa.sin_port), urioptions); + snprintf(invite, sizeof(invite), "sip:%s@%s:%d%s", n, p->tohost, ntohs(p->sa.sin_port), urioptions); } else { - snprintf(invite, sizeof(invite), "sip:%s@%s%s",p->username, p->tohost, urioptions); + snprintf(invite, sizeof(invite), "sip:%s@%s%s", n, p->tohost, urioptions); } } else if (ntohs(p->sa.sin_port) != 5060) { /* Needs to be 5060 */ snprintf(invite, sizeof(invite), "sip:%s:%d%s", p->tohost, ntohs(p->sa.sin_port), urioptions); @@ -4356,9 +4352,9 @@ snprintf(invite, sizeof(invite), "sip:%s%s", p->tohost, urioptions); } ast_copy_string(p->uri, invite, sizeof(p->uri)); + /* If there is a VXML URL append it to the SIP URL */ - if (vxml_url) - { + if (vxml_url) { snprintf(to, sizeof(to), "<%s>;%s", invite, vxml_url); } else { snprintf(to, sizeof(to), "<%s>", invite); @@ -5659,12 +5655,13 @@ /*--- register_verify: Verify registration of user */ static int register_verify(struct sip_pvt *p, struct sockaddr_in *sin, struct sip_request *req, char *uri, int ignore) { - int res = -1; + int res = -3; struct sip_peer *peer; char tmp[256] = ""; char iabuf[INET_ADDRSTRLEN]; char *name, *c; char *t; + /* Terminate URI */ t = uri; while(*t && (*t > 32) && (*t != ';')) @@ -5672,6 +5669,9 @@ *t = '\0'; ast_copy_string(tmp, get_header(req, "To"), sizeof(tmp)); + if (pedanticsipchecking) + url_decode(tmp); + c = get_in_brackets(tmp); /* Ditch ;user=phone */ name = strchr(c, ';'); @@ -5740,7 +5740,7 @@ switch (res) { case -1: /* Wrong password in authentication. Go away, don't try again until you fixed it */ - transmit_response(p, "403 Forbidden", &p->initreq); + transmit_response(p, "403 Forbidden (Bad auth)", &p->initreq); break; case -2: /* Username and digest username does not match. @@ -5749,6 +5749,13 @@ proper authentication by digest auth name */ transmit_response(p, "403 Authentication user name does not match account name", &p->initreq); break; + case -3: + /* URI not found */ + transmit_response(p, "404 Not found", &p->initreq); + break; + } + if (option_debug > 1) { + ast_log(LOG_DEBUG, "SIP REGISTER attempt failed for %s : %s\n", (res == -1) ? "Bad password" : ((res == -2 ) ? "Bad digest user" : "Peer not found")); } } if (peer) @@ -5796,10 +5803,16 @@ req = &p->initreq; if (req->rlPart2) ast_copy_string(tmp, req->rlPart2, sizeof(tmp)); - c = get_in_brackets(tmp); ast_copy_string(tmpf, get_header(req, "From"), sizeof(tmpf)); + + if (pedanticsipchecking) { + url_decode(tmp); + url_decode(tmpf); + } + fr = get_in_brackets(tmpf); + c = get_in_brackets(tmp); if (strncmp(c, "sip:", 4)) { ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c); @@ -5906,6 +5919,9 @@ ast_log(LOG_WARNING, "No Referrred-By Header That's not illegal\n"); return -1; } else { + if (pedanticsipchecking) { + url_decode(h_referred_by); + } referred_by = get_in_brackets(h_referred_by); } h_contact = get_header(req, "Contact"); @@ -6193,7 +6209,11 @@ t++; *t = '\0'; of = get_header(req, "From"); + if (pedanticsipchecking) + url_decode(of); + ast_copy_string(from, of, sizeof(from)); + memset(calleridname,0,sizeof(calleridname)); get_calleridname(from, calleridname, sizeof(calleridname)); @@ -9511,7 +9531,7 @@ /* Use this as the basis */ if (debug) - ast_verbose("Using latest request as basis request\n"); + ast_verbose("Using latest REGISTER request as basis request\n"); copy_request(&p->initreq, req); check_via(p, req); if ((res = register_verify(p, sin, req, e, ignore)) < 0)