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_BEARER_STR = { "Bearer", 6 },
63 pjsip_MD5_STR = { "md5", 3 },
64 pjsip_QUOTED_MD5_STR = { "\"md5\"", 5},
65 pjsip_AUTH_STR = { "auth", 4},
66 pjsip_QUOTED_AUTH_STR = { "\"auth\"", 6 };
67
68
parse_digest_credential(pj_scanner * scanner,pj_pool_t * pool,pjsip_digest_credential * cred)69 static void parse_digest_credential( pj_scanner *scanner, pj_pool_t *pool,
70 pjsip_digest_credential *cred)
71 {
72 pj_list_init(&cred->other_param);
73
74 for (;;) {
75 pj_str_t name, value;
76
77 pjsip_parse_param_imp(scanner, pool, &name, &value,
78 PJSIP_PARSE_REMOVE_QUOTE);
79
80 if (!pj_stricmp(&name, &pjsip_USERNAME_STR)) {
81 cred->username = value;
82
83 } else if (!pj_stricmp(&name, &pjsip_REALM_STR)) {
84 cred->realm = value;
85
86 } else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) {
87 cred->nonce = value;
88
89 } else if (!pj_stricmp(&name, &pjsip_URI_STR)) {
90 cred->uri = value;
91
92 } else if (!pj_stricmp(&name, &pjsip_RESPONSE_STR)) {
93 cred->response = value;
94
95 } else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) {
96 cred->algorithm = value;
97
98 } else if (!pj_stricmp(&name, &pjsip_CNONCE_STR)) {
99 cred->cnonce = value;
100
101 } else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) {
102 cred->opaque = value;
103
104 } else if (!pj_stricmp(&name, &pjsip_QOP_STR)) {
105 cred->qop = value;
106
107 } else if (!pj_stricmp(&name, &pjsip_NC_STR)) {
108 cred->nc = value;
109
110 } else {
111 pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param);
112 p->name = name;
113 p->value = value;
114 pj_list_insert_before(&cred->other_param, p);
115 }
116
117 /* Eat comma */
118 if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',')
119 pj_scan_get_char(scanner);
120 else
121 break;
122 }
123 }
124
parse_pgp_credential(pj_scanner * scanner,pj_pool_t * pool,pjsip_pgp_credential * cred)125 static void parse_pgp_credential( pj_scanner *scanner, pj_pool_t *pool,
126 pjsip_pgp_credential *cred)
127 {
128 PJ_UNUSED_ARG(scanner);
129 PJ_UNUSED_ARG(pool);
130 PJ_UNUSED_ARG(cred);
131
132 PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
133 }
134
parse_digest_challenge(pj_scanner * scanner,pj_pool_t * pool,pjsip_digest_challenge * chal)135 static void parse_digest_challenge( pj_scanner *scanner, pj_pool_t *pool,
136 pjsip_digest_challenge *chal)
137 {
138 pj_list_init(&chal->other_param);
139
140 for (;;) {
141 pj_str_t name, value, unquoted_value;
142
143 pjsip_parse_param_imp(scanner, pool, &name, &value, 0);
144
145 if (value.ptr && (value.ptr[0] == '"')) {
146 unquoted_value.ptr = value.ptr + 1;
147 unquoted_value.slen = value.slen - 2;
148 } else {
149 unquoted_value.ptr = value.ptr;
150 unquoted_value.slen = value.slen;
151 }
152
153 if (!pj_stricmp(&name, &pjsip_REALM_STR)) {
154 chal->realm = unquoted_value;
155
156 } else if (!pj_stricmp(&name, &pjsip_DOMAIN_STR)) {
157 chal->domain = unquoted_value;
158
159 } else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) {
160 chal->nonce = unquoted_value;
161
162 } else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) {
163 chal->opaque = unquoted_value;
164
165 } else if (!pj_stricmp(&name, &pjsip_STALE_STR)) {
166 if (!pj_stricmp(&value, &pjsip_TRUE_STR) ||
167 !pj_stricmp(&value, &pjsip_QUOTED_TRUE_STR))
168 {
169 chal->stale = 1;
170 }
171
172 } else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) {
173 chal->algorithm = unquoted_value;
174
175
176 } else if (!pj_stricmp(&name, &pjsip_QOP_STR)) {
177 chal->qop = unquoted_value;
178
179 } else {
180 pjsip_param *p = PJ_POOL_ALLOC_T(pool, pjsip_param);
181 p->name = name;
182 p->value = value;
183 pj_list_insert_before(&chal->other_param, p);
184 }
185
186 /* Eat comma */
187 if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',')
188 pj_scan_get_char(scanner);
189 else
190 break;
191 }
192 }
193
parse_pgp_challenge(pj_scanner * scanner,pj_pool_t * pool,pjsip_pgp_challenge * chal)194 static void parse_pgp_challenge( pj_scanner *scanner, pj_pool_t *pool,
195 pjsip_pgp_challenge *chal)
196 {
197 PJ_UNUSED_ARG(scanner);
198 PJ_UNUSED_ARG(pool);
199 PJ_UNUSED_ARG(chal);
200
201 PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
202 }
203
int_parse_hdr_authorization(pj_scanner * scanner,pj_pool_t * pool,pjsip_authorization_hdr * hdr)204 static void int_parse_hdr_authorization( pj_scanner *scanner, pj_pool_t *pool,
205 pjsip_authorization_hdr *hdr)
206 {
207 const pjsip_parser_const_t *pc = pjsip_parser_const();
208
209 if (*scanner->curptr == '"') {
210 pj_scan_get_quote(scanner, '"', '"', &hdr->scheme);
211 hdr->scheme.ptr++;
212 hdr->scheme.slen -= 2;
213 } else {
214 pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &hdr->scheme);
215 }
216
217 if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {
218
219 parse_digest_credential(scanner, pool, &hdr->credential.digest);
220
221 } else if (!pj_stricmp(&hdr->scheme, &pjsip_PGP_STR)) {
222
223 parse_pgp_credential( scanner, pool, &hdr->credential.pgp);
224
225 } else {
226 PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
227 }
228
229 pjsip_parse_end_hdr_imp( scanner );
230 }
231
int_parse_hdr_authenticate(pj_scanner * scanner,pj_pool_t * pool,pjsip_www_authenticate_hdr * hdr)232 static void int_parse_hdr_authenticate( pj_scanner *scanner, pj_pool_t *pool,
233 pjsip_www_authenticate_hdr *hdr)
234 {
235 const pjsip_parser_const_t *pc = pjsip_parser_const();
236
237 if (*scanner->curptr == '"') {
238 pj_scan_get_quote(scanner, '"', '"', &hdr->scheme);
239 hdr->scheme.ptr++;
240 hdr->scheme.slen -= 2;
241 } else {
242 pj_scan_get(scanner, &pc->pjsip_TOKEN_SPEC, &hdr->scheme);
243 }
244
245 if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {
246
247 parse_digest_challenge(scanner, pool, &hdr->challenge.digest);
248
249 } else if (!pj_stricmp(&hdr->scheme, &pjsip_PGP_STR)) {
250
251 parse_pgp_challenge(scanner, pool, &hdr->challenge.pgp);
252
253 } else {
254 PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
255 }
256
257 pjsip_parse_end_hdr_imp( scanner );
258 }
259
260
parse_hdr_authorization(pjsip_parse_ctx * ctx)261 static pjsip_hdr* parse_hdr_authorization( pjsip_parse_ctx *ctx )
262 {
263 pjsip_authorization_hdr *hdr = pjsip_authorization_hdr_create(ctx->pool);
264 int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr);
265 return (pjsip_hdr*)hdr;
266 }
267
parse_hdr_proxy_authorization(pjsip_parse_ctx * ctx)268 static pjsip_hdr* parse_hdr_proxy_authorization( pjsip_parse_ctx *ctx )
269 {
270 pjsip_proxy_authorization_hdr *hdr =
271 pjsip_proxy_authorization_hdr_create(ctx->pool);
272 int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr);
273 return (pjsip_hdr*)hdr;
274 }
275
parse_hdr_www_authenticate(pjsip_parse_ctx * ctx)276 static pjsip_hdr* parse_hdr_www_authenticate( pjsip_parse_ctx *ctx )
277 {
278 pjsip_www_authenticate_hdr *hdr =
279 pjsip_www_authenticate_hdr_create(ctx->pool);
280 int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr);
281 return (pjsip_hdr*)hdr;
282 }
283
parse_hdr_proxy_authenticate(pjsip_parse_ctx * ctx)284 static pjsip_hdr* parse_hdr_proxy_authenticate( pjsip_parse_ctx *ctx )
285 {
286 pjsip_proxy_authenticate_hdr *hdr =
287 pjsip_proxy_authenticate_hdr_create(ctx->pool);
288 int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr);
289 return (pjsip_hdr*)hdr;
290 }
291
292
pjsip_auth_init_parser()293 PJ_DEF(pj_status_t) pjsip_auth_init_parser()
294 {
295 pj_status_t status;
296
297 status = pjsip_register_hdr_parser( "Authorization", NULL,
298 &parse_hdr_authorization);
299 PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
300 status = pjsip_register_hdr_parser( "Proxy-Authorization", NULL,
301 &parse_hdr_proxy_authorization);
302 PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
303 status = pjsip_register_hdr_parser( "WWW-Authenticate", NULL,
304 &parse_hdr_www_authenticate);
305 PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
306 status = pjsip_register_hdr_parser( "Proxy-Authenticate", NULL,
307 &parse_hdr_proxy_authenticate);
308 PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
309
310 return PJ_SUCCESS;
311 }
312
pjsip_auth_deinit_parser()313 PJ_DEF(void) pjsip_auth_deinit_parser()
314 {
315 }
316
317