| /* $Id$ */ |
| /* |
| * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) |
| * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| #include <pjsip/sip_auth_parser.h> |
| #include <pjsip/sip_auth_msg.h> |
| #include <pjsip/sip_parser.h> |
| #include <pj/assert.h> |
| #include <pj/string.h> |
| #include <pj/except.h> |
| #include <pj/pool.h> |
| |
| static pjsip_hdr* parse_hdr_authorization ( pjsip_parse_ctx *ctx ); |
| static pjsip_hdr* parse_hdr_proxy_authorization ( pjsip_parse_ctx *ctx ); |
| static pjsip_hdr* parse_hdr_www_authenticate ( pjsip_parse_ctx *ctx ); |
| static pjsip_hdr* parse_hdr_proxy_authenticate ( pjsip_parse_ctx *ctx ); |
| |
| static void parse_digest_credential ( pj_scanner *scanner, pj_pool_t *pool, |
| pjsip_digest_credential *cred); |
| static void parse_pgp_credential ( pj_scanner *scanner, pj_pool_t *pool, |
| pjsip_pgp_credential *cred); |
| static void parse_digest_challenge ( pj_scanner *scanner, pj_pool_t *pool, |
| pjsip_digest_challenge *chal); |
| static void parse_pgp_challenge ( pj_scanner *scanner, pj_pool_t *pool, |
| pjsip_pgp_challenge *chal); |
| |
| const pj_str_t pjsip_USERNAME_STR = { "username", 8 }, |
| pjsip_REALM_STR = { "realm", 5}, |
| pjsip_NONCE_STR = { "nonce", 5}, |
| pjsip_URI_STR = { "uri", 3 }, |
| pjsip_RESPONSE_STR = { "response", 8 }, |
| pjsip_ALGORITHM_STR = { "algorithm", 9 }, |
| pjsip_DOMAIN_STR = { "domain", 6 }, |
| pjsip_STALE_STR = { "stale", 5}, |
| pjsip_QOP_STR = { "qop", 3}, |
| pjsip_CNONCE_STR = { "cnonce", 6}, |
| pjsip_OPAQUE_STR = { "opaque", 6}, |
| pjsip_NC_STR = { "nc", 2}, |
| pjsip_TRUE_STR = { "true", 4}, |
| pjsip_QUOTED_TRUE_STR = { "\"true\"", 6}, |
| pjsip_FALSE_STR = { "false", 5}, |
| pjsip_QUOTED_FALSE_STR = { "\"false\"", 7}, |
| pjsip_DIGEST_STR = { "Digest", 6}, |
| pjsip_QUOTED_DIGEST_STR = { "\"Digest\"", 8}, |
| pjsip_PGP_STR = { "PGP", 3 }, |
| pjsip_QUOTED_PGP_STR = { "\"PGP\"", 5 }, |
| pjsip_MD5_STR = { "md5", 3 }, |
| pjsip_QUOTED_MD5_STR = { "\"md5\"", 5}, |
| pjsip_AUTH_STR = { "auth", 4}, |
| pjsip_QUOTED_AUTH_STR = { "\"auth\"", 6 }; |
| |
| |
| static void parse_digest_credential( pj_scanner *scanner, pj_pool_t *pool, |
| pjsip_digest_credential *cred) |
| { |
| pj_list_init(&cred->other_param); |
| |
| for (;;) { |
| pj_str_t name, value; |
| |
| pjsip_parse_param_imp(scanner, pool, &name, &value, |
| PJSIP_PARSE_REMOVE_QUOTE); |
| |
| if (!pj_stricmp(&name, &pjsip_USERNAME_STR)) { |
| cred->username = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_REALM_STR)) { |
| cred->realm = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) { |
| cred->nonce = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_URI_STR)) { |
| cred->uri = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_RESPONSE_STR)) { |
| cred->response = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) { |
| cred->algorithm = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_CNONCE_STR)) { |
| cred->cnonce = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) { |
| cred->opaque = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_QOP_STR)) { |
| cred->qop = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_NC_STR)) { |
| cred->nc = value; |
| |
| } else { |
| pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param); |
| p->name = name; |
| p->value = value; |
| pj_list_insert_before(&cred->other_param, p); |
| } |
| |
| /* Eat comma */ |
| if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',') |
| pj_scan_get_char(scanner); |
| else |
| break; |
| } |
| } |
| |
| static void parse_pgp_credential( pj_scanner *scanner, pj_pool_t *pool, |
| pjsip_pgp_credential *cred) |
| { |
| PJ_UNUSED_ARG(scanner); |
| PJ_UNUSED_ARG(pool); |
| PJ_UNUSED_ARG(cred); |
| |
| PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); |
| } |
| |
| static void parse_digest_challenge( pj_scanner *scanner, pj_pool_t *pool, |
| pjsip_digest_challenge *chal) |
| { |
| pj_list_init(&chal->other_param); |
| |
| for (;;) { |
| pj_str_t name, value; |
| |
| pjsip_parse_param_imp(scanner, pool, &name, &value, |
| PJSIP_PARSE_REMOVE_QUOTE); |
| |
| if (!pj_stricmp(&name, &pjsip_REALM_STR)) { |
| chal->realm = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_DOMAIN_STR)) { |
| chal->domain = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) { |
| chal->nonce = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) { |
| chal->opaque = value; |
| |
| } else if (!pj_stricmp(&name, &pjsip_STALE_STR)) { |
| if (!pj_stricmp(&value, &pjsip_TRUE_STR) || |
| !pj_stricmp(&value, &pjsip_QUOTED_TRUE_STR)) |
| { |
| chal->stale = 1; |
| } |
| |
| } else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) { |
| chal->algorithm = value; |
| |
| |
| } else if (!pj_stricmp(&name, &pjsip_QOP_STR)) { |
| chal->qop = value; |
| |
| } else { |
| pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param); |
| p->name = name; |
| p->value = value; |
| pj_list_insert_before(&chal->other_param, p); |
| } |
| |
| /* Eat comma */ |
| if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',') |
| pj_scan_get_char(scanner); |
| else |
| break; |
| } |
| } |
| |
| static void parse_pgp_challenge( pj_scanner *scanner, pj_pool_t *pool, |
| pjsip_pgp_challenge *chal) |
| { |
| PJ_UNUSED_ARG(scanner); |
| PJ_UNUSED_ARG(pool); |
| PJ_UNUSED_ARG(chal); |
| |
| PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); |
| } |
| |
| static void int_parse_hdr_authorization( pj_scanner *scanner, pj_pool_t *pool, |
| pjsip_authorization_hdr *hdr) |
| { |
| const pjsip_parser_const_t *pc = pjsip_parser_const(); |
| |
| if (*scanner->curptr == '"') { |
| pj_scan_get_quote(scanner, '"', '"', &hdr->scheme); |
| hdr->scheme.ptr++; |
| hdr->scheme.slen -= 2; |
| } else { |
| pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &hdr->scheme); |
| } |
| |
| if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) { |
| |
| parse_digest_credential(scanner, pool, &hdr->credential.digest); |
| |
| } else if (!pj_stricmp(&hdr->scheme, &pjsip_PGP_STR)) { |
| |
| parse_pgp_credential( scanner, pool, &hdr->credential.pgp); |
| |
| } else { |
| PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); |
| } |
| |
| pjsip_parse_end_hdr_imp( scanner ); |
| } |
| |
| static void int_parse_hdr_authenticate( pj_scanner *scanner, pj_pool_t *pool, |
| pjsip_www_authenticate_hdr *hdr) |
| { |
| const pjsip_parser_const_t *pc = pjsip_parser_const(); |
| |
| if (*scanner->curptr == '"') { |
| pj_scan_get_quote(scanner, '"', '"', &hdr->scheme); |
| hdr->scheme.ptr++; |
| hdr->scheme.slen -= 2; |
| } else { |
| pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &hdr->scheme); |
| } |
| |
| if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) { |
| |
| parse_digest_challenge(scanner, pool, &hdr->challenge.digest); |
| |
| } else if (!pj_stricmp(&hdr->scheme, &pjsip_PGP_STR)) { |
| |
| parse_pgp_challenge(scanner, pool, &hdr->challenge.pgp); |
| |
| } else { |
| PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); |
| } |
| |
| pjsip_parse_end_hdr_imp( scanner ); |
| } |
| |
| |
| static pjsip_hdr* parse_hdr_authorization( pjsip_parse_ctx *ctx ) |
| { |
| pjsip_authorization_hdr *hdr = pjsip_authorization_hdr_create(ctx->pool); |
| int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr); |
| return (pjsip_hdr*)hdr; |
| } |
| |
| static pjsip_hdr* parse_hdr_proxy_authorization( pjsip_parse_ctx *ctx ) |
| { |
| pjsip_proxy_authorization_hdr *hdr = |
| pjsip_proxy_authorization_hdr_create(ctx->pool); |
| int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr); |
| return (pjsip_hdr*)hdr; |
| } |
| |
| static pjsip_hdr* parse_hdr_www_authenticate( pjsip_parse_ctx *ctx ) |
| { |
| pjsip_www_authenticate_hdr *hdr = |
| pjsip_www_authenticate_hdr_create(ctx->pool); |
| int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr); |
| return (pjsip_hdr*)hdr; |
| } |
| |
| static pjsip_hdr* parse_hdr_proxy_authenticate( pjsip_parse_ctx *ctx ) |
| { |
| pjsip_proxy_authenticate_hdr *hdr = |
| pjsip_proxy_authenticate_hdr_create(ctx->pool); |
| int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr); |
| return (pjsip_hdr*)hdr; |
| } |
| |
| |
| PJ_DEF(pj_status_t) pjsip_auth_init_parser() |
| { |
| pj_status_t status; |
| |
| status = pjsip_register_hdr_parser( "Authorization", NULL, |
| &parse_hdr_authorization); |
| PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); |
| status = pjsip_register_hdr_parser( "Proxy-Authorization", NULL, |
| &parse_hdr_proxy_authorization); |
| PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); |
| status = pjsip_register_hdr_parser( "WWW-Authenticate", NULL, |
| &parse_hdr_www_authenticate); |
| PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); |
| status = pjsip_register_hdr_parser( "Proxy-Authenticate", NULL, |
| &parse_hdr_proxy_authenticate); |
| PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); |
| |
| return PJ_SUCCESS; |
| } |
| |
| PJ_DEF(void) pjsip_auth_deinit_parser() |
| { |
| } |
| |