PJ_DEF(pj_str_t) pj_str_unescape( pj_pool_t *pool, const pj_str_t *src_str) { char *src = src_str->ptr; char *end = src + src_str->slen; pj_str_t dst_str; char *dst; if (pj_strchr(src_str, '%')==NULL) return *src_str; dst = dst_str.ptr = (char*) pj_pool_alloc(pool, src_str->slen); while (src != end) { if (*src == '%' && src < end-2 && pj_isxdigit(*(src+1)) && pj_isxdigit(*(src+2))) { *dst = (pj_uint8_t) ((pj_hex_digit_to_val(*(src+1)) << 4) + pj_hex_digit_to_val(*(src+2))); ++dst; src += 3; } else { *dst++ = *src++; } } dst_str.slen = dst - dst_str.ptr; return dst_str; }
PJ_DEF(void) pj_scan_get_unescape( pj_scanner *scanner, const pj_cis_t *spec, pj_str_t *out) { register char *s = scanner->curptr; char *dst = s; pj_assert(pj_cis_match(spec,0)==0); /* Must not match character '%' */ pj_assert(pj_cis_match(spec,'%')==0); /* EOF is detected implicitly */ if (!pj_cis_match(spec, *s) && *s != '%') { pj_scan_syntax_err(scanner); return; } out->ptr = s; do { if (*s == '%') { if (s+3 <= scanner->end && pj_isxdigit(*(s+1)) && pj_isxdigit(*(s+2))) { *dst = (pj_uint8_t) ((pj_hex_digit_to_val(*(s+1)) << 4) + pj_hex_digit_to_val(*(s+2))); ++dst; s += 3; } else { *dst++ = *s++; *dst++ = *s++; break; } } if (pj_cis_match(spec, *s)) { char *start = s; do { ++s; } while (pj_cis_match(spec, *s)); if (dst != start) pj_memmove(dst, start, s-start); dst += (s-start); } } while (*s == '%'); scanner->curptr = s; out->slen = (dst - out->ptr); if (PJ_SCAN_IS_PROBABLY_SPACE(*s) && scanner->skip_ws) { pj_scan_skip_whitespace(scanner); } }
PJ_DEF(unsigned long) pj_strtoul2(const pj_str_t *str, pj_str_t *endptr, unsigned base) { unsigned long value; unsigned i; PJ_CHECK_STACK(); value = 0; if (base <= 10) { for (i=0; i<(unsigned)str->slen; ++i) { unsigned c = (str->ptr[i] - '0'); if (c >= base) break; value = value * base + c; } } else if (base == 16) { for (i=0; i<(unsigned)str->slen; ++i) { if (!pj_isxdigit(str->ptr[i])) break; value = value * 16 + pj_hex_digit_to_val(str->ptr[i]); } } else { pj_assert(!"Unsupported base"); i = 0; value = 0xFFFFFFFFUL; } if (endptr) { endptr->ptr = str->ptr + i; endptr->slen = str->slen - i; } return value; }
PJ_DEF(pj_str_t*) pj_strcpy_unescape(pj_str_t *dst_str, const pj_str_t *src_str) { const char *src = src_str->ptr; const char *end = src + src_str->slen; char *dst = dst_str->ptr; while (src != end) { if (*src == '%' && src < end-2) { *dst = (pj_uint8_t) ((pj_hex_digit_to_val(*(src+1)) << 4) + pj_hex_digit_to_val(*(src+2))); ++dst; src += 3; } else { *dst++ = *src++; } } dst_str->slen = dst - dst_str->ptr; return dst_str; }
/* Return 0 if success or the index of the invalid char in the string */ static unsigned parse_quoted_string(struct parse_state *st, pj_str_t *output) { pj_str_t token; char *op, *ip, *iend; pj_scan_get_quote(&st->scanner, '"', '"', &token); /* Remove the quote characters */ token.ptr++; token.slen-=2; if (pj_strchr(&token, '\\') == NULL) { *output = token; return 0; } output->ptr = op = pj_pool_alloc(st->pool, token.slen); ip = token.ptr; iend = token.ptr + token.slen; while (ip != iend) { if (*ip == '\\') { ++ip; if (ip==iend) { goto on_error; } if (*ip == 'u') { ip++; if (iend - ip < 4) { ip = iend -1; goto on_error; } /* Only use the last two hext digits because we're on * ASCII */ *op++ = (char)(pj_hex_digit_to_val(ip[2]) * 16 + pj_hex_digit_to_val(ip[3])); ip += 4; } else if (*ip=='"' || *ip=='\\' || *ip=='/') { *op++ = *ip++; } else if (*ip=='b') { *op++ = '\b'; ip++; } else if (*ip=='f') { *op++ = '\f'; ip++; } else if (*ip=='n') { *op++ = '\n'; ip++; } else if (*ip=='r') { *op++ = '\r'; ip++; } else if (*ip=='t') { *op++ = '\t'; ip++; } else { goto on_error; } } else { *op++ = *ip++; } } output->slen = op - output->ptr; return 0; on_error: output->slen = op - output->ptr; return (unsigned)(ip - token.ptr); }
pj_status_t user_lookup(pj_pool_t *pool, const pjsip_auth_lookup_cred_param *param, pjsip_cred_info *cred_info, void* av_param) { const pj_str_t* acc_name = ¶m->acc_name; const pj_str_t* realm = ¶m->realm; const pjsip_rx_data* rdata = param->rdata; SAS::TrailId trail = get_trail(rdata); pj_status_t status = PJSIP_EAUTHACCNOTFOUND; // Get the impi and the nonce. There must be an authorization header otherwise // PJSIP wouldn't have called this method. std::string impi = PJUtils::pj_str_to_string(acc_name); pjsip_authorization_hdr* auth_hdr = (pjsip_authorization_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, NULL); std::string nonce = PJUtils::pj_str_to_string(&auth_hdr->credential.digest.nonce); // Get the Authentication Vector from the store. Json::Value* av = (Json::Value*)av_param; if (av == NULL) { LOG_WARNING("Received an authentication request for %s with nonce %s, but no matching AV found", impi.c_str(), nonce.c_str()); } if ((av != NULL) && (!verify_auth_vector(av, impi, trail))) { // Authentication vector is badly formed. av = NULL; // LCOV_EXCL_LINE } if (av != NULL) { pj_cstr(&cred_info->scheme, "digest"); pj_strdup(pool, &cred_info->username, acc_name); if (av->isMember("aka")) { // AKA authentication. The response in the AV must be used as a // plain-text password for the MD5 Digest computation. Convert the text // into binary as this is what PJSIP is expecting. std::string response = (*av)["aka"]["response"].asString(); std::string xres; for (size_t ii = 0; ii < response.length(); ii += 2) { xres.push_back((char)(pj_hex_digit_to_val(response[ii]) * 16 + pj_hex_digit_to_val(response[ii+1]))); } cred_info->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; pj_strdup2(pool, &cred_info->data, xres.c_str()); LOG_DEBUG("Found AKA XRES = %.*s", cred_info->data.slen, cred_info->data.ptr); // Use default realm as it isn't specified in the AV. pj_strdup(pool, &cred_info->realm, realm); status = PJ_SUCCESS; } else if (av->isMember("digest")) { if (pj_strcmp2(realm, (*av)["digest"]["realm"].asCString()) == 0) { // Digest authentication, so ha1 field is hashed password. cred_info->data_type = PJSIP_CRED_DATA_DIGEST; pj_strdup2(pool, &cred_info->data, (*av)["digest"]["ha1"].asCString()); cred_info->realm = *realm; LOG_DEBUG("Found Digest HA1 = %.*s", cred_info->data.slen, cred_info->data.ptr); status = PJ_SUCCESS; } else { // These credentials are for a different realm, so no credentials were // actually provided for us to check. status = PJSIP_EAUTHNOAUTH; } } correlate_branch_from_av(av, trail); } return status; }
PJ_DEF(pj_status_t) pj_strtoul3(const pj_str_t *str, unsigned long *value, unsigned base) { pj_str_t s; unsigned i; PJ_CHECK_STACK(); if (!str || !value) { return PJ_EINVAL; } s = *str; pj_strltrim(&s); if (s.slen == 0 || s.ptr[0] < '0' || (base <= 10 && (unsigned)s.ptr[0] > ('0' - 1) + base) || (base == 16 && !pj_isxdigit(s.ptr[0]))) { return PJ_EINVAL; } *value = 0; if (base <= 10) { for (i=0; i<(unsigned)s.slen; ++i) { unsigned c = s.ptr[i] - '0'; if (s.ptr[i] < '0' || (unsigned)s.ptr[i] > ('0' - 1) + base) { break; } if (*value > PJ_MAXULONG / base) { *value = PJ_MAXULONG; return PJ_ETOOBIG; } *value *= base; if ((PJ_MAXULONG - *value) < c) { *value = PJ_MAXULONG; return PJ_ETOOBIG; } *value += c; } } else if (base == 16) { for (i=0; i<(unsigned)s.slen; ++i) { unsigned c = pj_hex_digit_to_val(s.ptr[i]); if (!pj_isxdigit(s.ptr[i])) break; if (*value > PJ_MAXULONG / base) { *value = PJ_MAXULONG; return PJ_ETOOBIG; } *value *= base; if ((PJ_MAXULONG - *value) < c) { *value = PJ_MAXULONG; return PJ_ETOOBIG; } *value += c; } } else { pj_assert(!"Unsupported base"); return PJ_EINVAL; } return PJ_SUCCESS; }