Alexandre Lision | 8af73cb | 2013-12-10 14:11:20 -0500 | [diff] [blame] | 1 | /* $Id$ */ |
| 2 | /* |
| 3 | * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) |
| 4 | * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with this program; if not, write to the Free Software |
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 19 | */ |
| 20 | #include <pjsip/sip_auth_parser.h> |
| 21 | #include <pjsip/sip_auth_msg.h> |
| 22 | #include <pjsip/sip_parser.h> |
| 23 | #include <pj/assert.h> |
| 24 | #include <pj/string.h> |
| 25 | #include <pj/except.h> |
| 26 | #include <pj/pool.h> |
| 27 | |
| 28 | static pjsip_hdr* parse_hdr_authorization ( pjsip_parse_ctx *ctx ); |
| 29 | static pjsip_hdr* parse_hdr_proxy_authorization ( pjsip_parse_ctx *ctx ); |
| 30 | static pjsip_hdr* parse_hdr_www_authenticate ( pjsip_parse_ctx *ctx ); |
| 31 | static pjsip_hdr* parse_hdr_proxy_authenticate ( pjsip_parse_ctx *ctx ); |
| 32 | |
| 33 | static void parse_digest_credential ( pj_scanner *scanner, pj_pool_t *pool, |
| 34 | pjsip_digest_credential *cred); |
| 35 | static void parse_pgp_credential ( pj_scanner *scanner, pj_pool_t *pool, |
| 36 | pjsip_pgp_credential *cred); |
| 37 | static void parse_digest_challenge ( pj_scanner *scanner, pj_pool_t *pool, |
| 38 | pjsip_digest_challenge *chal); |
| 39 | static void parse_pgp_challenge ( pj_scanner *scanner, pj_pool_t *pool, |
| 40 | pjsip_pgp_challenge *chal); |
| 41 | |
| 42 | const pj_str_t pjsip_USERNAME_STR = { "username", 8 }, |
| 43 | pjsip_REALM_STR = { "realm", 5}, |
| 44 | pjsip_NONCE_STR = { "nonce", 5}, |
| 45 | pjsip_URI_STR = { "uri", 3 }, |
| 46 | pjsip_RESPONSE_STR = { "response", 8 }, |
| 47 | pjsip_ALGORITHM_STR = { "algorithm", 9 }, |
| 48 | pjsip_DOMAIN_STR = { "domain", 6 }, |
| 49 | pjsip_STALE_STR = { "stale", 5}, |
| 50 | pjsip_QOP_STR = { "qop", 3}, |
| 51 | pjsip_CNONCE_STR = { "cnonce", 6}, |
| 52 | pjsip_OPAQUE_STR = { "opaque", 6}, |
| 53 | pjsip_NC_STR = { "nc", 2}, |
| 54 | pjsip_TRUE_STR = { "true", 4}, |
| 55 | pjsip_QUOTED_TRUE_STR = { "\"true\"", 6}, |
| 56 | pjsip_FALSE_STR = { "false", 5}, |
| 57 | pjsip_QUOTED_FALSE_STR = { "\"false\"", 7}, |
| 58 | pjsip_DIGEST_STR = { "Digest", 6}, |
| 59 | pjsip_QUOTED_DIGEST_STR = { "\"Digest\"", 8}, |
| 60 | pjsip_PGP_STR = { "PGP", 3 }, |
| 61 | pjsip_QUOTED_PGP_STR = { "\"PGP\"", 5 }, |
| 62 | pjsip_MD5_STR = { "md5", 3 }, |
| 63 | pjsip_QUOTED_MD5_STR = { "\"md5\"", 5}, |
| 64 | pjsip_AUTH_STR = { "auth", 4}, |
| 65 | pjsip_QUOTED_AUTH_STR = { "\"auth\"", 6 }; |
| 66 | |
| 67 | |
| 68 | static void parse_digest_credential( pj_scanner *scanner, pj_pool_t *pool, |
| 69 | pjsip_digest_credential *cred) |
| 70 | { |
| 71 | pj_list_init(&cred->other_param); |
| 72 | |
| 73 | for (;;) { |
| 74 | pj_str_t name, value; |
| 75 | |
| 76 | pjsip_parse_param_imp(scanner, pool, &name, &value, |
| 77 | PJSIP_PARSE_REMOVE_QUOTE); |
| 78 | |
| 79 | if (!pj_stricmp(&name, &pjsip_USERNAME_STR)) { |
| 80 | cred->username = value; |
| 81 | |
| 82 | } else if (!pj_stricmp(&name, &pjsip_REALM_STR)) { |
| 83 | cred->realm = value; |
| 84 | |
| 85 | } else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) { |
| 86 | cred->nonce = value; |
| 87 | |
| 88 | } else if (!pj_stricmp(&name, &pjsip_URI_STR)) { |
| 89 | cred->uri = value; |
| 90 | |
| 91 | } else if (!pj_stricmp(&name, &pjsip_RESPONSE_STR)) { |
| 92 | cred->response = value; |
| 93 | |
| 94 | } else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) { |
| 95 | cred->algorithm = value; |
| 96 | |
| 97 | } else if (!pj_stricmp(&name, &pjsip_CNONCE_STR)) { |
| 98 | cred->cnonce = value; |
| 99 | |
| 100 | } else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) { |
| 101 | cred->opaque = value; |
| 102 | |
| 103 | } else if (!pj_stricmp(&name, &pjsip_QOP_STR)) { |
| 104 | cred->qop = value; |
| 105 | |
| 106 | } else if (!pj_stricmp(&name, &pjsip_NC_STR)) { |
| 107 | cred->nc = value; |
| 108 | |
| 109 | } else { |
| 110 | pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param); |
| 111 | p->name = name; |
| 112 | p->value = value; |
| 113 | pj_list_insert_before(&cred->other_param, p); |
| 114 | } |
| 115 | |
| 116 | /* Eat comma */ |
| 117 | if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',') |
| 118 | pj_scan_get_char(scanner); |
| 119 | else |
| 120 | break; |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | static void parse_pgp_credential( pj_scanner *scanner, pj_pool_t *pool, |
| 125 | pjsip_pgp_credential *cred) |
| 126 | { |
| 127 | PJ_UNUSED_ARG(scanner); |
| 128 | PJ_UNUSED_ARG(pool); |
| 129 | PJ_UNUSED_ARG(cred); |
| 130 | |
| 131 | PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); |
| 132 | } |
| 133 | |
| 134 | static void parse_digest_challenge( pj_scanner *scanner, pj_pool_t *pool, |
| 135 | pjsip_digest_challenge *chal) |
| 136 | { |
| 137 | pj_list_init(&chal->other_param); |
| 138 | |
| 139 | for (;;) { |
| 140 | pj_str_t name, value; |
| 141 | |
| 142 | pjsip_parse_param_imp(scanner, pool, &name, &value, |
| 143 | PJSIP_PARSE_REMOVE_QUOTE); |
| 144 | |
| 145 | if (!pj_stricmp(&name, &pjsip_REALM_STR)) { |
| 146 | chal->realm = value; |
| 147 | |
| 148 | } else if (!pj_stricmp(&name, &pjsip_DOMAIN_STR)) { |
| 149 | chal->domain = value; |
| 150 | |
| 151 | } else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) { |
| 152 | chal->nonce = value; |
| 153 | |
| 154 | } else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) { |
| 155 | chal->opaque = value; |
| 156 | |
| 157 | } else if (!pj_stricmp(&name, &pjsip_STALE_STR)) { |
| 158 | if (!pj_stricmp(&value, &pjsip_TRUE_STR) || |
| 159 | !pj_stricmp(&value, &pjsip_QUOTED_TRUE_STR)) |
| 160 | { |
| 161 | chal->stale = 1; |
| 162 | } |
| 163 | |
| 164 | } else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) { |
| 165 | chal->algorithm = value; |
| 166 | |
| 167 | |
| 168 | } else if (!pj_stricmp(&name, &pjsip_QOP_STR)) { |
| 169 | chal->qop = value; |
| 170 | |
| 171 | } else { |
| 172 | pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param); |
| 173 | p->name = name; |
| 174 | p->value = value; |
| 175 | pj_list_insert_before(&chal->other_param, p); |
| 176 | } |
| 177 | |
| 178 | /* Eat comma */ |
| 179 | if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',') |
| 180 | pj_scan_get_char(scanner); |
| 181 | else |
| 182 | break; |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | static void parse_pgp_challenge( pj_scanner *scanner, pj_pool_t *pool, |
| 187 | pjsip_pgp_challenge *chal) |
| 188 | { |
| 189 | PJ_UNUSED_ARG(scanner); |
| 190 | PJ_UNUSED_ARG(pool); |
| 191 | PJ_UNUSED_ARG(chal); |
| 192 | |
| 193 | PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); |
| 194 | } |
| 195 | |
| 196 | static void int_parse_hdr_authorization( pj_scanner *scanner, pj_pool_t *pool, |
| 197 | pjsip_authorization_hdr *hdr) |
| 198 | { |
| 199 | const pjsip_parser_const_t *pc = pjsip_parser_const(); |
| 200 | |
| 201 | if (*scanner->curptr == '"') { |
| 202 | pj_scan_get_quote(scanner, '"', '"', &hdr->scheme); |
| 203 | hdr->scheme.ptr++; |
| 204 | hdr->scheme.slen -= 2; |
| 205 | } else { |
| 206 | pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &hdr->scheme); |
| 207 | } |
| 208 | |
| 209 | if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) { |
| 210 | |
| 211 | parse_digest_credential(scanner, pool, &hdr->credential.digest); |
| 212 | |
| 213 | } else if (!pj_stricmp(&hdr->scheme, &pjsip_PGP_STR)) { |
| 214 | |
| 215 | parse_pgp_credential( scanner, pool, &hdr->credential.pgp); |
| 216 | |
| 217 | } else { |
| 218 | PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); |
| 219 | } |
| 220 | |
| 221 | pjsip_parse_end_hdr_imp( scanner ); |
| 222 | } |
| 223 | |
| 224 | static void int_parse_hdr_authenticate( pj_scanner *scanner, pj_pool_t *pool, |
| 225 | pjsip_www_authenticate_hdr *hdr) |
| 226 | { |
| 227 | const pjsip_parser_const_t *pc = pjsip_parser_const(); |
| 228 | |
| 229 | if (*scanner->curptr == '"') { |
| 230 | pj_scan_get_quote(scanner, '"', '"', &hdr->scheme); |
| 231 | hdr->scheme.ptr++; |
| 232 | hdr->scheme.slen -= 2; |
| 233 | } else { |
| 234 | pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &hdr->scheme); |
| 235 | } |
| 236 | |
| 237 | if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) { |
| 238 | |
| 239 | parse_digest_challenge(scanner, pool, &hdr->challenge.digest); |
| 240 | |
| 241 | } else if (!pj_stricmp(&hdr->scheme, &pjsip_PGP_STR)) { |
| 242 | |
| 243 | parse_pgp_challenge(scanner, pool, &hdr->challenge.pgp); |
| 244 | |
| 245 | } else { |
| 246 | PJ_THROW(PJSIP_SYN_ERR_EXCEPTION); |
| 247 | } |
| 248 | |
| 249 | pjsip_parse_end_hdr_imp( scanner ); |
| 250 | } |
| 251 | |
| 252 | |
| 253 | static pjsip_hdr* parse_hdr_authorization( pjsip_parse_ctx *ctx ) |
| 254 | { |
| 255 | pjsip_authorization_hdr *hdr = pjsip_authorization_hdr_create(ctx->pool); |
| 256 | int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr); |
| 257 | return (pjsip_hdr*)hdr; |
| 258 | } |
| 259 | |
| 260 | static pjsip_hdr* parse_hdr_proxy_authorization( pjsip_parse_ctx *ctx ) |
| 261 | { |
| 262 | pjsip_proxy_authorization_hdr *hdr = |
| 263 | pjsip_proxy_authorization_hdr_create(ctx->pool); |
| 264 | int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr); |
| 265 | return (pjsip_hdr*)hdr; |
| 266 | } |
| 267 | |
| 268 | static pjsip_hdr* parse_hdr_www_authenticate( pjsip_parse_ctx *ctx ) |
| 269 | { |
| 270 | pjsip_www_authenticate_hdr *hdr = |
| 271 | pjsip_www_authenticate_hdr_create(ctx->pool); |
| 272 | int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr); |
| 273 | return (pjsip_hdr*)hdr; |
| 274 | } |
| 275 | |
| 276 | static pjsip_hdr* parse_hdr_proxy_authenticate( pjsip_parse_ctx *ctx ) |
| 277 | { |
| 278 | pjsip_proxy_authenticate_hdr *hdr = |
| 279 | pjsip_proxy_authenticate_hdr_create(ctx->pool); |
| 280 | int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr); |
| 281 | return (pjsip_hdr*)hdr; |
| 282 | } |
| 283 | |
| 284 | |
| 285 | PJ_DEF(pj_status_t) pjsip_auth_init_parser() |
| 286 | { |
| 287 | pj_status_t status; |
| 288 | |
| 289 | status = pjsip_register_hdr_parser( "Authorization", NULL, |
| 290 | &parse_hdr_authorization); |
| 291 | PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); |
| 292 | status = pjsip_register_hdr_parser( "Proxy-Authorization", NULL, |
| 293 | &parse_hdr_proxy_authorization); |
| 294 | PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); |
| 295 | status = pjsip_register_hdr_parser( "WWW-Authenticate", NULL, |
| 296 | &parse_hdr_www_authenticate); |
| 297 | PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); |
| 298 | status = pjsip_register_hdr_parser( "Proxy-Authenticate", NULL, |
| 299 | &parse_hdr_proxy_authenticate); |
| 300 | PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); |
| 301 | |
| 302 | return PJ_SUCCESS; |
| 303 | } |
| 304 | |
| 305 | PJ_DEF(void) pjsip_auth_deinit_parser() |
| 306 | { |
| 307 | } |
| 308 | |